session tab on openvidu-testapp

pull/20/head
pabloFuente 2017-09-27 18:42:11 +02:00
parent 3a12428be8
commit d44ba5fd61
14 changed files with 184 additions and 385 deletions

View File

@ -8,15 +8,13 @@ import { AppMaterialModule } from './app.material.module';
import { routing } from './app.routing'; import { routing } from './app.routing';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { DashboardComponent } from './components/dashboard/dashboard.component'; import { DashboardComponent } from './components/dashboard/dashboard.component';
import { SessionComponent } from './components/session/session.component';
import { OpenviduRestService } from './services/openvidu-rest.service'; import { OpenviduRestService } from './services/openvidu-rest.service';
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
DashboardComponent, DashboardComponent
SessionComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,

View File

@ -2,16 +2,11 @@ import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router'; import { Routes, RouterModule } from '@angular/router';
import { DashboardComponent } from './components/dashboard/dashboard.component'; import { DashboardComponent } from './components/dashboard/dashboard.component';
import { SessionComponent } from './components/session/session.component';
const appRoutes: Routes = [ const appRoutes: Routes = [
{ {
path: '', path: '',
component: DashboardComponent component: DashboardComponent
},
{
path: 'session/:session-name',
component: SessionComponent
} }
]; ];

View File

@ -1,41 +0,0 @@
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {
MdButtonModule,
MdIconModule,
MdCheckboxModule,
MdCardModule,
MdInputModule,
MdProgressSpinnerModule,
MdTooltipModule,
MdDialogModule,
MdSlideToggleModule
} from '@angular/material';
@NgModule({
imports: [
BrowserAnimationsModule,
MdButtonModule,
MdIconModule,
MdCheckboxModule,
MdCardModule,
MdInputModule,
MdProgressSpinnerModule,
MdTooltipModule,
MdDialogModule,
MdSlideToggleModule
],
exports: [
BrowserAnimationsModule,
MdButtonModule,
MdIconModule,
MdCheckboxModule,
MdCardModule,
MdInputModule,
MdProgressSpinnerModule,
MdTooltipModule,
MdDialogModule,
MdSlideToggleModule
],
})
export class AppMaterialModule { }

View File

@ -27,99 +27,31 @@ th {
} }
md-card { md-card {
font-weight: bold; background-color: rgba(77, 77, 77, 0.05);
} }
#join-dialog h1 { .join-card {
color: #4d4d4d; width: fit-content;
font-weight: bold; margin: auto;
text-align: center; margin-bottom: 50px;
margin-top: 50px;
} }
#img-div { .full-width {
text-align: center; width: 100%;
position: absolute;
top: 19%;
left: 50%;
transform: translate(-50%, -50%);
} }
#img-div img { .inner-card {
height: 15%; border: 1px solid #e1e1e1;
} padding: 16px;
background: #ffffff;
#join-dialog label {
color: #0088aa;
}
#join-dialog input.btn {
margin-top: 15px;
}
#session-header {
margin-bottom: 20px;
}
#session-title {
display: inline-block;
}
#buttonLeaveSession {
float: right;
margin-top: 20px; margin-top: 20px;
} }
#video-container video { .inner-card h4 {
position: relative; margin-top: 0;
float: left;
cursor: pointer;
} }
#video-container p { .inner-card md-radio-group {
display: inline-block; padding-left: 20px;
background: #f8f8f8; }
padding-right: 5px;
padding-left: 5px;
color: #777777;
font-weight: bold;
border-bottom-right-radius: 4px;
}
video {
width: 100%;
height: auto;
}
#main-video p {
position: absolute;
display: inline-block;
background: #f8f8f8;
padding-right: 5px;
padding-left: 5px;
left: 0;
font-size: 22px;
color: #777777;
font-weight: bold;
border-bottom-right-radius: 4px;
}
#main-video video {
cursor: initial;
}
#session img {
width: 100%;
height: auto;
display: inline-block;
object-fit: contain;
vertical-align: baseline;
}
#session #video-container img {
position: relative;
float: left;
width: 50%;
cursor: pointer;
object-fit: cover;
height: 180px;
}

View File

@ -1,44 +1,83 @@
<md-form-field class="example-full-width"> <md-form-field>
<input mdInput placeholder="OpenVidu Server URL" [(ngModel)]="openviduURL"> <input mdInput placeholder="OpenVidu Server URL" [(ngModel)]="openviduURL">
</md-form-field> </md-form-field>
<md-tab-group class="demo-tab-group" dynamicHeight="true" selectedIndex="5"> <md-form-field>
<md-tab id="audio-video" label="Audio + Video"> <input mdInput placeholder="OpenVidu Server Secret" [(ngModel)]="openviduSecret">
</md-form-field>
<md-tab-group class="demo-tab-group" dynamicHeight="true">
<md-tab id="audio-video" label="Test session">
<div class="demo-tab-content"> <div class="demo-tab-content">
</div> <div fxLayout="row" fxLayoutGap="20px" fxFlex="40" fxLayoutAlign="start start">
</md-tab> <md-card class="join-card">
<md-tab id="audio-only" label="Audio only"> <md-card-title>Join a session</md-card-title>
<div class="demo-tab-content"> <md-card-content>
<form>
<md-form-field class="full-width">
<input mdInput placeholder="Client data" name="clientData" [(ngModel)]="clientData">
</md-form-field>
<md-form-field class="full-width">
<input mdInput placeholder="Session name" name="sessionName" [(ngModel)]="sessionName">
</md-form-field>
<div class="inner-card">
<h4>Send...</h4>
<p>
<md-checkbox [(ngModel)]="sendVideo" name="sendVideo">Video</md-checkbox>
</p>
<p>
<md-radio-group [(ngModel)]="optionVideo" name="optionVideo" [disabled]="!sendVideo">
<md-radio-button value="video">Video</md-radio-button>
<md-radio-button value="screen">Screen</md-radio-button>
</md-radio-group>
</p>
<p>
<md-checkbox [(ngModel)]="sendAudio" name="sendAudio">Audio</md-checkbox>
</p>
</div>
<div class="inner-card">
<h4>Enter with active...</h4>
<md-checkbox [(ngModel)]="activeVideo" name="activeVideo" [disabled]="!sendVideo">Video</md-checkbox>
<md-checkbox [(ngModel)]="activeAudio" name="activeAudio" [disabled]="!sendAudio">Audio</md-checkbox>
</div>
</form>
</md-card-content>
<md-card-actions>
<button md-button id="join-btn" (click)="joinSession()">JOIN</button>
</md-card-actions>
</md-card>
</div>
<div *ngIf="session" fxLayout="row" fxLayoutGap="20px" fxFlex="60" fxLayoutAlign="start start">
<div id="session">
<div id="session-header">
<h1 id="session-title">{{sessionName}}</h1>
<button md-raised-button color="warn" (click)="leaveSession()">Leave session</button>
</div>
<div id="video-container"></div>
</div>
</div>
</div> </div>
</md-tab> </md-tab>
<md-tab id="video-only" label="Video only">
</md-tab> <div fxLayout="row" fxLayoutGap="20px" fxLayoutAlign="start space-around">
<md-tab id="screen-audio" label="Screen + Audio">
<div class="demo-tab-content"> </div>
</div>
</md-tab>
<md-tab id="screen-only" label="Screen only">
<div class="demo-tab-content">
</div>
</md-tab>
<md-tab id="api-rest" label="API REST"> <md-tab id="api-rest" label="API REST">
<div class="demo-tab-content"> <div class="demo-tab-content">
<md-form-field>
<input mdInput placeholder="OpenVidu Server Secret" [(ngModel)]="openviduSecret">
</md-form-field>
<button md-raised-button color="primary" (click)="cleanAllSessions()" style="float: right">Clean sessions</button>
<div fxLayout="row" fxLayoutGap="20px" fxLayoutAlign="start space-around"> <div fxLayout="row" fxLayoutGap="20px" fxLayoutAlign="start space-around">
<div fxLayout="column" fxFlex="50" fxFlexAlign="center" fxFill> <div fxLayout="column" fxFlex="45" fxFlexAlign="center" fxFill>
<button md-raised-button color="primary" (click)="getSessionId()">Get sessionId</button> <button md-raised-button color="primary" (click)="getSessionId()">Get sessionId</button>
</div> </div>
<div fxLayout="column" fxFlex="50" fxFlexAlign="center" fxFill> <div fxLayout="column" fxFlex="45" fxFlexAlign="center" fxFill>
<button md-raised-button color="primary" (click)="getToken()" [disabled]="getTokenDisabled()">Get token</button> <button md-raised-button color="primary" (click)="getToken()" [disabled]="getTokenDisabled()">Get token</button>
</div> </div>
<div fxLayout="column" fxFlex="10" fxFlexAlign="center" fxFill>
<button md-raised-button color="warn" (click)="cleanAllSessions()" [disabled]="data.length == 0">Clean sessions</button>
</div>
</div> </div>
<div id="table-row" fxLayout="row" fxLayoutGap="20px" fxLayoutAlign="start"> <div id="table-row" fxLayout="row" fxLayoutGap="20px" fxLayoutAlign="start">
@ -90,23 +129,3 @@
</div> </div>
</md-tab> </md-tab>
</md-tab-group> </md-tab-group>
<!--<div id="join">
<div id="img-div"><img src="assets/images/openvidu_grey_bg_transp_cropped.png" /></div>
<div id="join-dialog" class="jumbotron vertical-center">
<h1>Join a video session</h1>
<form class="form-group" (submit)="joinSession()">
<p>
<label>Participant</label>
<input class="form-control" type="text" id="clientData" name="clientData" [(ngModel)]="clientData" required>
</p>
<p>
<label>Session</label>
<input class="form-control" type="text" id="sessionName" name="sessionName" [(ngModel)]="sessionName" required>
</p>
<p class="text-center">
<input class="btn btn-lg btn-success" type="submit" name="commit" value="Join!">
</p>
</form>
</div>
</div>-->

View File

@ -4,7 +4,7 @@ import { DataSource } from '@angular/cdk/table';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of'; import 'rxjs/add/observable/of';
import { OpenVidu } from 'openvidu-browser'; import { OpenVidu, Session } from 'openvidu-browser';
import * as colormap from 'colormap'; import * as colormap from 'colormap';
const numColors = 64; const numColors = 64;
@ -26,9 +26,19 @@ export class DashboardComponent implements OnInit {
openViduRoles = ['SUBSCRIBER', 'PUBLISHER', 'MODERATOR']; openViduRoles = ['SUBSCRIBER', 'PUBLISHER', 'MODERATOR'];
sendAudio = true;
sendVideo = true;
optionVideo = 'video';
activeAudio = true;
activeVideo = true;
// Join form // Join form
sessionName: string;
clientData: string; clientData: string;
sessionName: string;
// OpenVidu objects
OV: OpenVidu;
session: Session;
// API REST data collected // API REST data collected
data = []; data = [];
@ -48,11 +58,94 @@ export class DashboardComponent implements OnInit {
ngOnInit() { } ngOnInit() { }
/* TEST SESSION TAB */
private generateSessionInfo() { private generateSessionInfo() {
this.sessionName = 'TestSession'; this.sessionName = 'TestSession';
this.clientData = 'RandomClient' + Math.floor(Math.random() * 100); this.clientData = 'TestClient';
} }
private removeHttps = input => input.replace(/^https?:\/\//, '');
private joinSession(): void {
this.OV = new OpenVidu();
this.session = this.OV.initSession('wss://'
+ this.removeHttps(this.openviduURL)
+ '/'
+ this.sessionName + '?secret='
+ this.openviduSecret);
this.session.on('streamCreated', (event) => {
const subscriber = this.session.subscribe(event.stream, 'video-container');
subscriber.on('videoElementCreated', (e) => {
this.appendUserData(e.element, subscriber.stream.connection.data, subscriber.stream.connection);
});
});
this.session.on('streamDestroyed', (event) => {
this.removeUserData(event.stream.connection);
});
this.session.connect(null, this.clientData, (error) => {
if (!error) {
const publisher = this.OV.initPublisher('video-container', {
audio: true,
video: true,
quality: 'MEDIUM'
});
publisher.on('videoElementCreated', (event) => {
this.appendUserData(event.element, this.clientData, null);
event.element['muted'] = true;
});
this.session.publish(publisher);
} else {
console.log('There was an error connecting to the session:', error.code, error.message);
}
});
}
private leaveSession(): void {
if (this.session) {
this.session.disconnect();
}
this.session = null;
this.OV = null;
}
private appendUserData(videoElement, data, connection) {
const dataNode = document.createElement('div');
dataNode.className = 'data-node';
dataNode.id = 'data-' + (connection ? connection.connectionId : data);
dataNode.innerHTML = '<p>' + data + '</p>';
videoElement.parentNode.insertBefore(dataNode, videoElement.nextSibling);
}
private removeUserData(connection) {
$('#data-' + connection.connectionId).remove();
}
private removeAllUserData() {
const nicknameElements = $('.data-node');
while (nicknameElements[0]) {
nicknameElements[0].remove();
}
}
/* TEST SESSION TAB */
/* API REST TAB */
private getSessionId() { private getSessionId() {
this.openviduRestService.getSessionId(this.openviduURL, this.openviduSecret) this.openviduRestService.getSessionId(this.openviduURL, this.openviduSecret)
.then((sessionId) => { .then((sessionId) => {
@ -92,4 +185,7 @@ export class DashboardComponent implements OnInit {
this.openviduRestService.sessionIdSession.clear(); this.openviduRestService.sessionIdSession.clear();
this.openviduRestService.sessionIdTokenOpenViduRole.clear(); this.openviduRestService.sessionIdTokenOpenViduRole.clear();
} }
/* API REST TAB */
} }

View File

@ -1,11 +0,0 @@
<div *ngIf="session" id="session">
<div id="session-header">
<h1 id="session-title">{{sessionName}}</h1>
<input class="btn btn-large btn-danger" type="button" id="buttonLeaveSession" (click)="leaveSession()" value="Leave session">
</div>
<div id="main-video" class="col-md-6">
<p></p>
<video #mainVideoElement autoplay></video>
</div>
<div id="video-container" class="col-md-6"></div>
</div>

View File

@ -1,25 +0,0 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SessionComponent } from './session.component';
describe('SessionComponent', () => {
let component: SessionComponent;
let fixture: ComponentFixture<SessionComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SessionComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SessionComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,135 +0,0 @@
import { OpenVidu, Session } from 'openvidu-browser';
import { Component, ElementRef, ViewChild, HostListener, OnDestroy } from '@angular/core';
declare var $: any;
@Component({
selector: 'app-session',
templateUrl: './session.component.html',
styleUrls: ['./session.component.css']
})
export class SessionComponent implements OnDestroy {
@ViewChild('mainVideoElement') elementRef: ElementRef;
mainVideoElement: HTMLVideoElement;
// OpenVidu objects
OV: OpenVidu;
session: Session;
// Join form
sessionName: string;
clientData: string;
constructor() { }
@HostListener('window:beforeunload')
beforeunloadHandler() {
// On window closed leave session
this.leaveSession();
}
ngOnDestroy() {
// On component destroyed leave session
this.leaveSession();
}
joinSession() {
this.OV = new OpenVidu();
this.session = this.OV.initSession('wss://' + location.hostname + ':8443/' + this.sessionName + '?secret=MY_SECRET');
this.mainVideoElement = this.elementRef.nativeElement;
this.session.on('streamCreated', (event) => {
const subscriber = this.session.subscribe(event.stream, 'video-container');
subscriber.on('videoElementCreated', (e) => {
this.appendUserData(e.element, subscriber.stream.connection);
});
});
this.session.on('streamDestroyed', (event) => {
this.removeUserData(event.stream.connection);
});
this.session.connect(null, this.clientData, (error) => {
if (!error) {
const publisher = this.OV.initPublisher('video-container', {
audio: true,
video: true,
quality: 'MEDIUM'
});
publisher.on('videoElementCreated', (event) => {
this.initMainVideo(event.element, this.clientData);
this.appendUserData(event.element, this.clientData);
event.element['muted'] = true;
});
this.session.publish(publisher);
} else {
console.log('There was an error connecting to the session:', error.code, error.message);
}
});
return false;
}
leaveSession() {
if (this.OV) {
this.session.disconnect();
}
this.removeAllUserData();
this.session = null;
this.OV = null;
}
private appendUserData(videoElement, connection) {
let userData;
let nodeId;
if (typeof connection === 'string') {
userData = connection;
nodeId = connection;
} else {
userData = JSON.parse(connection.data).clientData;
nodeId = connection.connectionId;
}
const dataNode = document.createElement('div');
dataNode.className = 'data-node';
dataNode.id = 'data-' + nodeId;
dataNode.innerHTML = '<p>' + userData + '</p>';
videoElement.parentNode.insertBefore(dataNode, videoElement.nextSibling);
this.addClickListener(videoElement, userData);
}
private removeUserData(connection) {
const dataNode = $('#data-' + connection.connectionId);
dataNode.parentNode.removeChild(dataNode);
}
private removeAllUserData() {
const nicknameElements = $('.data-node');
while (nicknameElements[0]) {
nicknameElements[0].parentNode.removeChild(nicknameElements[0]);
}
}
private addClickListener(videoElement: HTMLVideoElement, userData) {
videoElement.addEventListener('click', () => {
const mainUserData = $('#main-video p');
if (this.mainVideoElement.srcObject !== videoElement.srcObject) {
mainUserData.innerHTML = userData;
this.mainVideoElement.srcObject = videoElement.srcObject;
}
});
}
private initMainVideo(videoElement: HTMLVideoElement, userData) {
this.mainVideoElement.srcObject = videoElement.srcObject;
$('#main-video p').innerHTML = userData;
this.mainVideoElement['muted'] = true;
}
}

View File

@ -31,7 +31,6 @@ export class OpenviduRestService {
getToken(openviduURL: string, openviduSecret: string, sessionId: string, role: string, serverData: string): Promise<string> { getToken(openviduURL: string, openviduSecret: string, sessionId: string, role: string, serverData: string): Promise<string> {
console.warn(sessionId); console.warn(sessionId);
const OV = new OpenViduAPI(openviduURL, openviduSecret);
const session: SessionAPI = this.sessionIdSession.get(sessionId); const session: SessionAPI = this.sessionIdSession.get(sessionId);
const OVRole: OpenViduRoleAPI = OpenViduRoleAPI[role]; const OVRole: OpenViduRoleAPI = OpenViduRoleAPI[role];

View File

@ -1,15 +0,0 @@
import { TestBed, inject } from '@angular/core/testing';
import { SessionConfService } from './session-conf.service';
describe('SessionConfService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [SessionConfService]
});
});
it('should be created', inject([SessionConfService], (service: SessionConfService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -1,17 +0,0 @@
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class SessionConfService {
private conf$ = new Subject();
getConf() {
return this.conf$;
}
updateConf(configuration: any) {
this.conf$.next(configuration);
}
}

View File

@ -20,3 +20,7 @@ ul {
list-style: none; list-style: none;
padding-left: 0; padding-left: 0;
} }
video {
max-width: 300px;
}