diff --git a/openvidu-testapp/src/app/app.component.html b/openvidu-testapp/src/app/app.component.html index 9933d7b3..a0633a48 100644 --- a/openvidu-testapp/src/app/app.component.html +++ b/openvidu-testapp/src/app/app.component.html @@ -3,14 +3,15 @@
SESSIONS + SCENARIOS API REST
- + - + diff --git a/openvidu-testapp/src/app/app.material.module.ts b/openvidu-testapp/src/app/app.material.module.ts index 15a89525..d8d850c3 100644 --- a/openvidu-testapp/src/app/app.material.module.ts +++ b/openvidu-testapp/src/app/app.material.module.ts @@ -19,7 +19,8 @@ import { MatExpansionModule, MatSlideToggleModule, MatSidenavModule, - MatFormFieldModule + MatFormFieldModule, + MatBadgeModule } from '@angular/material'; @NgModule({ @@ -43,7 +44,8 @@ import { MatExpansionModule, MatSlideToggleModule, MatSidenavModule, - MatFormFieldModule + MatFormFieldModule, + MatBadgeModule ], }) export class AppMaterialModule { } diff --git a/openvidu-testapp/src/app/app.module.ts b/openvidu-testapp/src/app/app.module.ts index cd832bd8..85da573d 100644 --- a/openvidu-testapp/src/app/app.module.ts +++ b/openvidu-testapp/src/app/app.module.ts @@ -1,23 +1,29 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { FormsModule } from '@angular/forms'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { FlexLayoutModule } from '@angular/flex-layout'; import { AppMaterialModule } from './app.material.module'; +import { HttpClientModule } from '@angular/common/http'; import { routing } from './app.routing'; import { AppComponent } from './app.component'; import { TestSessionsComponent } from './components/test-sessions/test-sessions.component'; import { TestApirestComponent } from './components/test-apirest/test-apirest.component'; +import { TestScenariosComponent } from './components/test-scenarios/test-scenarios.component'; import { OpenviduInstanceComponent } from './components/openvidu-instance/openvidu-instance.component'; import { VideoComponent } from './components/video/video.component'; import { OpenViduVideoComponent } from './components/video/ov-video.component'; -import { ExtensionDialogComponent } from './components/dialogs/extension-dialog.component'; -import { LocalRecordingDialogComponent } from './components/dialogs/local-recording-dialog.component'; -import { SessionPropertiesDialogComponent } from './components/dialogs/session-properties-dialog.component'; -import { SessionApiDialogComponent } from './components/dialogs/session-api-dialog.component'; -import { EventsDialogComponent } from './components/dialogs/events-dialog.component'; -import { PublisherPropertiesDialogComponent } from './components/dialogs/publisher-properties-dialog.component'; +import { UsersTableComponent } from './components/users-table/users-table.component'; +import { TableVideoComponent } from './components/users-table/table-video.component'; + +import { ExtensionDialogComponent } from './components/dialogs/extension-dialog/extension-dialog.component'; +import { LocalRecordingDialogComponent } from './components/dialogs/local-recording-dialog/local-recording-dialog.component'; +import { SessionPropertiesDialogComponent } from './components/dialogs/session-properties-dialog/session-properties-dialog.component'; +import { SessionApiDialogComponent } from './components/dialogs/session-api-dialog/session-api-dialog.component'; +import { EventsDialogComponent } from './components/dialogs/events-dialog/events-dialog.component'; +import { PublisherPropertiesDialogComponent } from './components/dialogs/publisher-properties-dialog/publisher-properties-dialog.component'; +import { ScenarioPropertiesDialogComponent } from './components/dialogs/scenario-properties-dialog/scenario-properties-dialog.component'; import { OpenviduRestService } from './services/openvidu-rest.service'; import { OpenviduParamsService } from './services/openvidu-params.service'; @@ -32,12 +38,16 @@ import { MuteSubscribersService } from './services/mute-subscribers.service'; OpenViduVideoComponent, TestSessionsComponent, TestApirestComponent, + TestScenariosComponent, ExtensionDialogComponent, SessionPropertiesDialogComponent, SessionApiDialogComponent, EventsDialogComponent, LocalRecordingDialogComponent, - PublisherPropertiesDialogComponent + PublisherPropertiesDialogComponent, + ScenarioPropertiesDialogComponent, + UsersTableComponent, + TableVideoComponent ], imports: [ BrowserModule, @@ -45,6 +55,7 @@ import { MuteSubscribersService } from './services/mute-subscribers.service'; BrowserAnimationsModule, AppMaterialModule, FlexLayoutModule, + HttpClientModule, routing ], providers: [ @@ -59,7 +70,8 @@ import { MuteSubscribersService } from './services/mute-subscribers.service'; SessionApiDialogComponent, EventsDialogComponent, LocalRecordingDialogComponent, - PublisherPropertiesDialogComponent + PublisherPropertiesDialogComponent, + ScenarioPropertiesDialogComponent ], bootstrap: [AppComponent] }) diff --git a/openvidu-testapp/src/app/app.routing.ts b/openvidu-testapp/src/app/app.routing.ts index e1fb6e64..27b70a8c 100644 --- a/openvidu-testapp/src/app/app.routing.ts +++ b/openvidu-testapp/src/app/app.routing.ts @@ -2,6 +2,7 @@ import { ModuleWithProviders } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { TestSessionsComponent } from './components/test-sessions/test-sessions.component'; +import { TestScenariosComponent } from './components/test-scenarios/test-scenarios.component'; import { TestApirestComponent } from './components/test-apirest/test-apirest.component'; const appRoutes: Routes = [ @@ -12,6 +13,10 @@ const appRoutes: Routes = [ path: 'test-sessions', component: TestSessionsComponent }, + { + path: 'test-scenarios', + component: TestScenariosComponent + }, { path: 'test-apirest', component: TestApirestComponent diff --git a/openvidu-testapp/src/app/components/dialogs/events-dialog.component.ts b/openvidu-testapp/src/app/components/dialogs/events-dialog/events-dialog.component.ts similarity index 100% rename from openvidu-testapp/src/app/components/dialogs/events-dialog.component.ts rename to openvidu-testapp/src/app/components/dialogs/events-dialog/events-dialog.component.ts diff --git a/openvidu-testapp/src/app/components/dialogs/extension-dialog.component.ts b/openvidu-testapp/src/app/components/dialogs/extension-dialog/extension-dialog.component.ts similarity index 100% rename from openvidu-testapp/src/app/components/dialogs/extension-dialog.component.ts rename to openvidu-testapp/src/app/components/dialogs/extension-dialog/extension-dialog.component.ts diff --git a/openvidu-testapp/src/app/components/dialogs/local-recording-dialog.component.ts b/openvidu-testapp/src/app/components/dialogs/local-recording-dialog/local-recording-dialog.component.ts similarity index 100% rename from openvidu-testapp/src/app/components/dialogs/local-recording-dialog.component.ts rename to openvidu-testapp/src/app/components/dialogs/local-recording-dialog/local-recording-dialog.component.ts diff --git a/openvidu-testapp/src/app/components/dialogs/publisher-properties-dialog.component.css b/openvidu-testapp/src/app/components/dialogs/publisher-properties-dialog/publisher-properties-dialog.component.css similarity index 100% rename from openvidu-testapp/src/app/components/dialogs/publisher-properties-dialog.component.css rename to openvidu-testapp/src/app/components/dialogs/publisher-properties-dialog/publisher-properties-dialog.component.css diff --git a/openvidu-testapp/src/app/components/dialogs/publisher-properties-dialog.component.html b/openvidu-testapp/src/app/components/dialogs/publisher-properties-dialog/publisher-properties-dialog.component.html similarity index 100% rename from openvidu-testapp/src/app/components/dialogs/publisher-properties-dialog.component.html rename to openvidu-testapp/src/app/components/dialogs/publisher-properties-dialog/publisher-properties-dialog.component.html diff --git a/openvidu-testapp/src/app/components/dialogs/publisher-properties-dialog.component.ts b/openvidu-testapp/src/app/components/dialogs/publisher-properties-dialog/publisher-properties-dialog.component.ts similarity index 90% rename from openvidu-testapp/src/app/components/dialogs/publisher-properties-dialog.component.ts rename to openvidu-testapp/src/app/components/dialogs/publisher-properties-dialog/publisher-properties-dialog.component.ts index 6783b4ae..a9838f17 100644 --- a/openvidu-testapp/src/app/components/dialogs/publisher-properties-dialog.component.ts +++ b/openvidu-testapp/src/app/components/dialogs/publisher-properties-dialog/publisher-properties-dialog.component.ts @@ -1,7 +1,6 @@ import { Component, Inject } from '@angular/core'; -import { MatDialog, MAT_DIALOG_DATA, MatDialogConfig, MatDialogRef, MAT_CHECKBOX_CLICK_ACTION } from '@angular/material'; +import { MAT_DIALOG_DATA, MatDialogRef, MAT_CHECKBOX_CLICK_ACTION } from '@angular/material'; -import { SessionProperties, MediaMode, RecordingMode, RecordingLayout } from 'openvidu-node-client'; import { PublisherProperties, OpenVidu } from 'openvidu-browser'; @Component({ @@ -27,10 +26,6 @@ export class PublisherPropertiesDialogComponent { audioDevices = []; videoDevices = []; - private mediaMode = MediaMode; - private recordingMode = RecordingMode; - private defaultRecordingLayout = RecordingLayout; - constructor(public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: PublisherProperties) { this.publisherProperties = data; diff --git a/openvidu-testapp/src/app/components/dialogs/scenario-properties-dialog/scenario-properties-dialog.component.css b/openvidu-testapp/src/app/components/dialogs/scenario-properties-dialog/scenario-properties-dialog.component.css new file mode 100644 index 00000000..3f8afb3b --- /dev/null +++ b/openvidu-testapp/src/app/components/dialogs/scenario-properties-dialog/scenario-properties-dialog.component.css @@ -0,0 +1,73 @@ +mat-chip { + margin: 0 0 5px 0 !important; + height: 25px; + max-width: 180px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + cursor: pointer !important; +} + +mat-divider { + margin-top: 10px !important; + margin-bottom: 5px !important; +} + +button.device-btn { + height: 30px; + width: 30px; + line-height: 30px; +} + +button.device-btn mat-icon { + width: 20px; + height: 20px; + font-size: 20px; + line-height: 20px; +} + +div.mat-form-field-subscript-wrapper { + margin-top: 0 !important; +} + +mat-checkbox { + margin-right: 4px; +} + +mat-radio-button { + margin-left: 5px; + font-size: 14px; +} + +mat-radio-button:first-child { + margin-left: 0; +} + +.not-manual { + padding-top: 6px; + padding-bottom: 25px; +} + +.conf-label { + display: block; + font-size: 12px; + color: rgba(0, 0, 0, 0.54); + font-weight: 400; + margin-bottom: 5px; +} + +.conf-label { + display: block; + font-size: 12px; + color: rgba(0, 0, 0, 0.54); + font-weight: 400; + margin-bottom: 5px; +} + +#manual-turn-div { + margin-top: 10px; + margin-bottom: 25px; + padding: 5px; + border: 1px solid #00000026; + border-radius: 3px; +} \ No newline at end of file diff --git a/openvidu-testapp/src/app/components/dialogs/scenario-properties-dialog/scenario-properties-dialog.component.html b/openvidu-testapp/src/app/components/dialogs/scenario-properties-dialog/scenario-properties-dialog.component.html new file mode 100644 index 00000000..6b86944c --- /dev/null +++ b/openvidu-testapp/src/app/components/dialogs/scenario-properties-dialog/scenario-properties-dialog.component.html @@ -0,0 +1,61 @@ +
+

Scenario properties

+ + +
+ + Auto + Freeice + Manual + +
+ + + + + + + + + +
+
+ + Audio + Video + + + + + + + + {{audioDevice.label}} + + + + + + + + {{videoDevice.label}} + + + + + + + + +
+ + +
\ No newline at end of file diff --git a/openvidu-testapp/src/app/components/dialogs/scenario-properties-dialog/scenario-properties-dialog.component.ts b/openvidu-testapp/src/app/components/dialogs/scenario-properties-dialog/scenario-properties-dialog.component.ts new file mode 100644 index 00000000..4757e515 --- /dev/null +++ b/openvidu-testapp/src/app/components/dialogs/scenario-properties-dialog/scenario-properties-dialog.component.ts @@ -0,0 +1,109 @@ +import { Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef, MAT_CHECKBOX_CLICK_ACTION } from '@angular/material'; + +import { PublisherProperties, OpenVidu } from 'openvidu-browser'; + +@Component({ + selector: 'app-scenario-properties-dialog', + templateUrl: './scenario-properties-dialog.component.html', + styleUrls: ['./scenario-properties-dialog.component.css'], + providers: [ + { provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'noop' } + ] +}) +export class ScenarioPropertiesDialogComponent { + + OV: OpenVidu; + publisherProperties: PublisherProperties; + initValue: PublisherProperties; + + audioSource; + videoSource; + + audioSourceAux; + videoSourceAux; + + audioDevices = []; + videoDevices = []; + + turnConf: string; + manualTurnConf: RTCIceServer = {}; + + constructor(public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data) { + this.publisherProperties = data.publisherProperties; + this.OV = new OpenVidu(); + this.initValue = Object.assign({}, this.publisherProperties); + this.audioSource = typeof this.publisherProperties.audioSource === 'string' ? this.publisherProperties.audioSource : undefined; + this.videoSource = typeof this.publisherProperties.videoSource === 'string' ? this.publisherProperties.videoSource : undefined; + this.turnConf = data.turnConf; + this.manualTurnConf = data.manualTurnConf; + } + + toggleAudio(): void { + if (this.publisherProperties.audioSource === false) { + this.publisherProperties.audioSource = this.audioSource; + this.audioSource = this.audioSourceAux; + } else { + this.audioSourceAux = this.audioSource; + this.audioSource = undefined; + this.publisherProperties.audioSource = false; + } + } + + toggleVideo(): void { + if (this.publisherProperties.videoSource === false) { + this.publisherProperties.videoSource = this.videoSource; + this.videoSource = this.videoSourceAux; + } else { + this.videoSourceAux = this.videoSource; + this.videoSource = undefined; + this.publisherProperties.videoSource = false; + } + } + + setCloseValue() { + if (typeof this.audioSource === 'string') { + if (!!this.audioSource) { + this.publisherProperties.audioSource = this.audioSource; + } else { + this.publisherProperties.audioSource = undefined; + } + } + if (typeof this.videoSource === 'string') { + if (!!this.videoSource) { + this.publisherProperties.videoSource = this.videoSource; + } else { + this.publisherProperties.videoSource = undefined; + } + } + return { + publisherProperties: this.publisherProperties, + turnConf: this.turnConf, + manualTurnConf: this.manualTurnConf + }; + } + + listAudioDevices() { + this.audioDevices = []; + this.OV.getDevices().then(devices => { + devices.forEach(device => { + if (device.kind === 'audioinput') { + this.audioDevices.push(device); + } + }); + }); + } + + listVideoDevices() { + this.videoDevices = []; + this.OV.getDevices().then(devices => { + devices.forEach(device => { + if (device.kind === 'videoinput') { + this.videoDevices.push(device); + } + }); + }); + } + +} diff --git a/openvidu-testapp/src/app/components/dialogs/session-api-dialog.component.ts b/openvidu-testapp/src/app/components/dialogs/session-api-dialog/session-api-dialog.component.ts similarity index 96% rename from openvidu-testapp/src/app/components/dialogs/session-api-dialog.component.ts rename to openvidu-testapp/src/app/components/dialogs/session-api-dialog/session-api-dialog.component.ts index 6925e9e4..05e3ba00 100644 --- a/openvidu-testapp/src/app/components/dialogs/session-api-dialog.component.ts +++ b/openvidu-testapp/src/app/components/dialogs/session-api-dialog/session-api-dialog.component.ts @@ -1,7 +1,6 @@ import { Component, Inject } from '@angular/core'; -import { MatDialog, MAT_DIALOG_DATA, MatDialogConfig, MatDialogRef } from '@angular/material'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; -import { Session } from 'openvidu-browser'; import { OpenVidu as OpenViduAPI } from 'openvidu-node-client'; @Component({ diff --git a/openvidu-testapp/src/app/components/dialogs/session-properties-dialog.component.css b/openvidu-testapp/src/app/components/dialogs/session-properties-dialog/session-properties-dialog.component.css similarity index 100% rename from openvidu-testapp/src/app/components/dialogs/session-properties-dialog.component.css rename to openvidu-testapp/src/app/components/dialogs/session-properties-dialog/session-properties-dialog.component.css diff --git a/openvidu-testapp/src/app/components/dialogs/session-properties-dialog.component.html b/openvidu-testapp/src/app/components/dialogs/session-properties-dialog/session-properties-dialog.component.html similarity index 100% rename from openvidu-testapp/src/app/components/dialogs/session-properties-dialog.component.html rename to openvidu-testapp/src/app/components/dialogs/session-properties-dialog/session-properties-dialog.component.html diff --git a/openvidu-testapp/src/app/components/dialogs/session-properties-dialog.component.ts b/openvidu-testapp/src/app/components/dialogs/session-properties-dialog/session-properties-dialog.component.ts similarity index 100% rename from openvidu-testapp/src/app/components/dialogs/session-properties-dialog.component.ts rename to openvidu-testapp/src/app/components/dialogs/session-properties-dialog/session-properties-dialog.component.ts diff --git a/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts b/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts index 7ecdc271..6f7d4653 100644 --- a/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts +++ b/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts @@ -1,31 +1,27 @@ import { - Component, Input, HostListener, ChangeDetectorRef, SimpleChanges, ElementRef, ViewChild, + Component, Input, HostListener, ChangeDetectorRef, SimpleChanges, OnInit, OnDestroy, OnChanges } from '@angular/core'; -import { Subscription } from 'rxjs'; import { - OpenVidu, Session, Subscriber, Publisher, Stream, Connection, - LocalRecorder, VideoInsertMode, StreamEvent, ConnectionEvent, - SessionDisconnectedEvent, SignalEvent, RecordingEvent, VideoElementEvent, - PublisherSpeakingEvent, StreamManagerEvent, StreamManager, PublisherProperties + OpenVidu, Session, Subscriber, Publisher, VideoInsertMode, StreamEvent, ConnectionEvent, + SessionDisconnectedEvent, SignalEvent, RecordingEvent, + PublisherSpeakingEvent, PublisherProperties } from 'openvidu-browser'; import { OpenVidu as OpenViduAPI, - Session as SessionAPI, SessionProperties as SessionPropertiesAPI, MediaMode, RecordingMode, RecordingLayout } from 'openvidu-node-client'; -import { MatDialog, MatDialogRef, MAT_CHECKBOX_CLICK_ACTION } from '@angular/material'; -import { ExtensionDialogComponent } from '../dialogs/extension-dialog.component'; -import { LocalRecordingDialogComponent } from '../dialogs/local-recording-dialog.component'; +import { MatDialog, MAT_CHECKBOX_CLICK_ACTION } from '@angular/material'; +import { ExtensionDialogComponent } from '../dialogs/extension-dialog/extension-dialog.component'; import { TestFeedService } from '../../services/test-feed.service'; -import { EventsDialogComponent } from '../dialogs/events-dialog.component'; -import { SessionPropertiesDialogComponent } from '../dialogs/session-properties-dialog.component'; -import { SessionApiDialogComponent } from '../dialogs/session-api-dialog.component'; -import { PublisherPropertiesDialogComponent } from '../dialogs/publisher-properties-dialog.component'; +import { EventsDialogComponent } from '../dialogs/events-dialog/events-dialog.component'; +import { SessionPropertiesDialogComponent } from '../dialogs/session-properties-dialog/session-properties-dialog.component'; +import { SessionApiDialogComponent } from '../dialogs/session-api-dialog/session-api-dialog.component'; +import { PublisherPropertiesDialogComponent } from '../dialogs/publisher-properties-dialog/publisher-properties-dialog.component'; export interface SessionConf { @@ -119,15 +115,9 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy { openviduError: any; - private publisherRecorder: LocalRecorder; - private publisherRecording = false; - private publisherPaused = false; - private muteSubscribersSubscription: Subscription; - constructor( private changeDetector: ChangeDetectorRef, private dialog: MatDialog, - private recordDialog: MatDialog, private testFeedService: TestFeedService ) { this.generateSessionInfo(); diff --git a/openvidu-testapp/src/app/components/test-apirest/test-apirest.component.html b/openvidu-testapp/src/app/components/test-apirest/test-apirest.component.html index b9fc6a81..02e6e2e5 100644 --- a/openvidu-testapp/src/app/components/test-apirest/test-apirest.component.html +++ b/openvidu-testapp/src/app/components/test-apirest/test-apirest.component.html @@ -75,8 +75,8 @@ {{sid[0]}} - -

{{token}}

+ +

{{token}}

diff --git a/openvidu-testapp/src/app/components/test-scenarios/test-scenarios.component.css b/openvidu-testapp/src/app/components/test-scenarios/test-scenarios.component.css new file mode 100644 index 00000000..60790150 --- /dev/null +++ b/openvidu-testapp/src/app/components/test-scenarios/test-scenarios.component.css @@ -0,0 +1,32 @@ +#finish-btn { + float: right; +} + +app-openvidu-instance { + display: inline-flex; + margin: 25px 5px 0px 0px; +} + +.scenario-input { + width: 40px; +} + +.scenario-input { + margin-left: 10px; +} + +.scenario-input:first-of-type { + margin-right: 25px; +} + +.report-div { + margin-top: 50px; +} + +.report-field { + width: 100%; +} + +#back-report-btn { + float: right; +} \ No newline at end of file diff --git a/openvidu-testapp/src/app/components/test-scenarios/test-scenarios.component.html b/openvidu-testapp/src/app/components/test-scenarios/test-scenarios.component.html new file mode 100644 index 00000000..6e01ba85 --- /dev/null +++ b/openvidu-testapp/src/app/components/test-scenarios/test-scenarios.component.html @@ -0,0 +1,30 @@ +
+ + + + + + + + + + +
+ +
+ +
+ +
+ + Report + + + +
\ No newline at end of file diff --git a/openvidu-testapp/src/app/components/test-scenarios/test-scenarios.component.spec.ts b/openvidu-testapp/src/app/components/test-scenarios/test-scenarios.component.spec.ts new file mode 100644 index 00000000..dafcd550 --- /dev/null +++ b/openvidu-testapp/src/app/components/test-scenarios/test-scenarios.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TestScenariosComponent } from './test-scenarios.component'; + +describe('TestScenariosComponent', () => { + let component: TestScenariosComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ TestScenariosComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TestScenariosComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/openvidu-testapp/src/app/components/test-scenarios/test-scenarios.component.ts b/openvidu-testapp/src/app/components/test-scenarios/test-scenarios.component.ts new file mode 100644 index 00000000..6f1f840c --- /dev/null +++ b/openvidu-testapp/src/app/components/test-scenarios/test-scenarios.component.ts @@ -0,0 +1,470 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { MatDialog } from '@angular/material'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Subscription } from 'rxjs'; + +import { SessionConf } from '../openvidu-instance/openvidu-instance.component'; +import { OpenviduParamsService } from '../../services/openvidu-params.service'; +import { TestFeedService } from '../../services/test-feed.service'; +import { ScenarioPropertiesDialogComponent } from '../dialogs/scenario-properties-dialog/scenario-properties-dialog.component'; +import { StreamManagerWrapper } from '../users-table/table-video.component'; + +import { + OpenVidu, + Session, + StreamEvent, + StreamManagerEvent, + PublisherProperties, + ConnectionEvent +} from 'openvidu-browser'; +import { + OpenVidu as OpenViduAPI, + SessionProperties as SessionPropertiesAPI, + MediaMode, + RecordingMode, + RecordingLayout +} from 'openvidu-node-client'; + +@Component({ + selector: 'app-test-scenarios', + templateUrl: './test-scenarios.component.html', + styleUrls: ['./test-scenarios.component.css'] +}) +export class TestScenariosComponent implements OnInit, OnDestroy { + + fixedSessionId = 'SCENARIO_TEST'; + + openviduUrl: string; + openviduSecret: string; + + scenarioPlaying = false; + + paramsSubscription: Subscription; + eventsInfoSubscription: Subscription; + + // OpenViduInstance collection + users: SessionConf[] = []; + connections: string[] = []; + publishers: StreamManagerWrapper[] = []; + subscribers: { connectionId: string, subs: StreamManagerWrapper[] }[] = []; + totalNumberOfStreams = 0; + manyToMany = 2; + oneToMany = 2; + + // OpenVidu Browser objects + OVs: OpenVidu[] = []; + sessions: Session[] = []; + + // OpenVidu Node Client objects + sessionProperties: SessionPropertiesAPI = { + mediaMode: MediaMode.ROUTED, + recordingMode: RecordingMode.MANUAL, + defaultRecordingLayout: RecordingLayout.BEST_FIT, + defaultCustomLayout: '', + customSessionId: '' + }; + + turnConf = 'auto'; + manualTurnConf: RTCIceServer = { urls: [] }; + + publisherProperties: PublisherProperties = { + audioSource: false, + videoSource: undefined, + frameRate: 2, + resolution: '320x240', + mirror: true, + publishAudio: true, + publishVideo: true + }; + + report; + numberOfReports = 0; + stringifyAllReports = ''; + textAreaValue = ''; + isFocusedOnReport = false; + + constructor( + private openviduParamsService: OpenviduParamsService, + private testFeedService: TestFeedService, + private dialog: MatDialog, + private http: HttpClient + ) { } + + ngOnInit() { + const openviduParams = this.openviduParamsService.getParams(); + this.openviduUrl = openviduParams.openviduUrl; + this.openviduSecret = openviduParams.openviduSecret; + + this.paramsSubscription = this.openviduParamsService.newParams$.subscribe( + params => { + this.openviduUrl = params.openviduUrl; + this.openviduSecret = params.openviduSecret; + }); + + this.eventsInfoSubscription = this.testFeedService.newLastEvent$.subscribe( + newEvent => { + (window as any).myEvents += ('
' + JSON.stringify(newEvent)); + }); + } + + ngOnDestroy() { + this.endScenario(); + this.paramsSubscription.unsubscribe(); + this.eventsInfoSubscription.unsubscribe(); + } + + loadScenario(subsPubs: number, pubs: number, subs: number): void { + + this.totalNumberOfStreams = pubs + subsPubs; // Number of outgoing streams + this.totalNumberOfStreams += pubs * (subs + subsPubs); // Publishers only times total number of subscribers + if (subsPubs > 0) { + // Publihsers/Subscribers times total number of subscribers (minus 1 for not being subscribed to their own publisher) + this.totalNumberOfStreams += subsPubs * (subs + (subsPubs - 1)); + } + + this.users = []; + this.report = { 'streamsOut': { 'count': 0, 'items': [] }, 'streamsIn': { 'count': 0, 'items': [] } }; + this.loadSubsPubs(subsPubs); + this.loadPubs(pubs); + this.loadSubs(subs); + this.startSession(); + this.scenarioPlaying = true; + } + + endScenario() { + for (const session of this.sessions) { + session.disconnect(); + } + this.publishers = []; + this.subscribers = []; + this.OVs = []; + this.sessions = []; + this.connections = []; + this.scenarioPlaying = false; + delete this.report; + this.numberOfReports = 0; + this.textAreaValue = ''; + this.stringifyAllReports = ''; + } + + private loadSubsPubs(n: number): void { + for (let i = 0; i < n; i++) { + this.users.push({ + subscribeTo: true, + publishTo: true, + startSession: true + }); + } + } + + private loadSubs(n: number): void { + for (let i = 0; i < n; i++) { + this.users.push({ + subscribeTo: true, + publishTo: false, + startSession: true + }); + } + } + + private loadPubs(n: number): void { + for (let i = 0; i < n; i++) { + this.users.push({ + subscribeTo: false, + publishTo: true, + startSession: true + }); + } + } + + private startSession() { + for (const user of this.users) { + + this.getToken().then(token => { + const OV = new OpenVidu(); + const session = OV.initSession(); + + this.OVs.push(OV); + this.sessions.push(session); + + session.on('connectionCreated', (event: ConnectionEvent) => { + if (this.connections.indexOf(event.connection.connectionId) === -1) { + this.connections.push(event.connection.connectionId); + } + }); + + if (user.subscribeTo) { + session.on('streamCreated', (event: StreamEvent) => { + const subscriber = session.subscribe(event.stream, undefined, (error) => { + const subAux = this.subscribers + .find(s => s.connectionId === session.connection.connectionId).subs + .find(s => s.streamManager.stream.connection.connectionId === subscriber.stream.connection.connectionId); + if (!!error) { + subAux.state['errorConnecting'] = Date.now(); + } else { + subAux.state['connected'] = Date.now(); + } + }); + + const sub = this.subscribers.find(s => s.connectionId === session.connection.connectionId); + if (!sub) { + this.subscribers.push({ + connectionId: session.connection.connectionId, + subs: [{ + connectionId: session.connection.connectionId, + streamManager: subscriber, + state: { 'connecting': Date.now() } + }] + }); + } else { + sub.subs.push({ + connectionId: session.connection.connectionId, + streamManager: subscriber, + state: { 'connecting': Date.now() } + }); + } + + subscriber.on('streamPlaying', (e: StreamManagerEvent) => { + this.subscribers + .find(s => s.connectionId === session.connection.connectionId).subs + .find(s => s.streamManager.stream.connection.connectionId === subscriber.stream.connection.connectionId) + .state['playing'] = Date.now(); + }); + }); + } + + session.connect(token) + .then(() => { + if (user.publishTo) { + + const publisher = OV.initPublisher(undefined, this.publisherProperties); + const publisherWrapper = { + connectionId: session.connection.connectionId, + streamManager: publisher, + state: { 'connecting': Date.now() } + }; + + publisher.on('streamCreated', () => { + publisherWrapper.state['connected'] = Date.now(); + }); + publisher.on('streamPlaying', () => { + publisherWrapper.state['playing'] = Date.now(); + }); + session.publish(publisher).catch(() => { + publisherWrapper.state['errorConnecting'] = Date.now(); + }); + this.publishers.push(publisherWrapper); + + } + }) + .catch(); + }); + } + } + + private getToken(): Promise { + const OV_NodeClient = new OpenViduAPI(this.openviduUrl, this.openviduSecret); + if (!this.sessionProperties.customSessionId) { + this.sessionProperties.customSessionId = this.fixedSessionId; + } + return OV_NodeClient.createSession(this.sessionProperties) + .then(session_NodeClient => { + return session_NodeClient.generateToken(); + }); + } + + openScenarioPropertiesDialog() { + const dialogRef = this.dialog.open(ScenarioPropertiesDialogComponent, { + data: { + publisherProperties: this.publisherProperties, + turnConf: this.turnConf, + manualTurnConf: this.manualTurnConf + }, + width: '300px', + disableClose: true + }); + + dialogRef.afterClosed().subscribe(result => { + if (!!result) { + this.publisherProperties = result.publisherProperties; + this.turnConf = result.turnConf; + this.manualTurnConf = result.manualTurnConf; + } + }); + } + + addReportForStream(event: StreamManagerWrapper) { + + const getSessionInfo = () => { + let headers = new HttpHeaders(); + headers = headers.append('Authorization', 'Basic ' + btoa('OPENVIDUAPP:' + this.openviduSecret)); + this.http.get(this.openviduUrl + 'api/sessions/' + this.fixedSessionId, { headers }).subscribe( + sessionInfo => { + + this.report.streamsOut.items.forEach(report => { + const streamOutRemoteInfo = sessionInfo['connections'] + .find(c => c.connectionId === report.connectionId).publishers + .find(p => { + report.webrtcTagName = p.webrtcTagName; + return p.webrtcTagName === report.streamId; + }); + report.remoteCandidatePair = { + localCandidate: this.parseRemoteCandidatePair(streamOutRemoteInfo.localCandidate), + remoteCandidate: this.parseRemoteCandidatePair(streamOutRemoteInfo.remoteCandidate) + }; + }); + + this.report.streamsIn.items.forEach(report => { + const streamInRemoteInfo = sessionInfo['connections'] + .find(c => c.connectionId === report.connectionId).subscribers + .find(p => { + report.webrtcTagName = p.webrtcTagName; + return p.webrtcTagName === report.connectionId + '_' + report.streamId; + }); + report.remoteCandidatePair = { + localCandidate: this.parseRemoteCandidatePair(streamInRemoteInfo.localCandidate), + remoteCandidate: this.parseRemoteCandidatePair(streamInRemoteInfo.remoteCandidate) + }; + }); + + this.stringifyAllReports = JSON.stringify(this.report, null, '\t'); + if (!this.textAreaValue) { + this.textAreaValue = this.stringifyAllReports; + } + }, + error => { } + ); + }; + + event.streamManager.stream.getSelectedIceCandidate() + .then(localCandidatePair => { + + let newReport; + + if (event.streamManager.remote) { + newReport = { + connectionId: event.connectionId, + streamId: event.streamManager.stream.streamId, + state: event.state, + localCandidatePair: { + localCandidate: localCandidatePair.localCandidate, + remoteCandidate: localCandidatePair.remoteCandidate + }, + remoteCandidatePair: { + localCandidate: {}, + remoteCandidate: {} + } + }; + + this.report.streamsIn.count++; + this.report.streamsIn.items.push(newReport); + } else { + newReport = { + connectionId: event.connectionId, + streamId: event.streamManager.stream.streamId, + state: event.state, + localCandidatePair: { + localCandidate: localCandidatePair.localCandidate, + remoteCandidate: localCandidatePair.remoteCandidate + }, + remoteCandidatePair: { + localCandidate: {}, + remoteCandidate: {} + } + }; + + this.report.streamsOut.count++; + this.report.streamsOut.items.push(newReport); + } + + if (++this.numberOfReports === this.totalNumberOfStreams) { + getSessionInfo(); + } + + }) + .catch(); + } + + private parseRemoteCandidatePair(candidateStr: string) { + const array = candidateStr.split(/\s+/); + return { + portNumber: array[5], + ipAddress: array[4], + transport: array[2].toLowerCase(), + candidateType: array[7], + priority: array[3] + }; + } + + focusOnReportForStream(event) { + this.isFocusedOnReport = true; + let jsonObject = !!event.in ? this.report.streamsIn : this.report.streamsOut; + jsonObject = jsonObject.items.find(stream => { + const webrtcTagName = !!event.in ? event.connectionId + '_' + event.streamId : event.streamId; + return (stream.connectionId === event.connectionId && stream.webrtcTagName === webrtcTagName); + }); + this.textAreaValue = JSON.stringify(jsonObject, null, '\t'); + } + + /*addReportForStreamConcurrent(event: StreamManagerWrapper) { + let headers = new HttpHeaders(); + headers = headers.append('Authorization', 'Basic ' + btoa('OPENVIDUAPP:' + this.openviduSecret)); + this.http.get(this.openviduUrl + 'api/sessions/' + this.fixedSessionId, { headers }).subscribe( + sessionInfo => { + + event.streamManager.stream.getSelectedIceCandidate() + .then(localCandidatePair => { + let newReport; + if (event.streamManager.remote) { + const streamInRemoteInfo = sessionInfo['connections'] + .find(c => c.connectionId === event.connectionId).subscribers + .find(p => p.webrtcTagName === event.connectionId + '_' + event.streamManager.stream.streamId); + + newReport = { + connectionId: event.connectionId, + streamId: event.streamManager.stream.streamId, + state: event.state, + localCandidatePair: { + localCandidate: localCandidatePair.localCandidate, + remoteCandidate: localCandidatePair.remoteCandidate + }, + remoteCandidatePair: { + localCandidate: streamInRemoteInfo.localCandidate, + remoteCandidate: streamInRemoteInfo.remoteCandidate + } + }; + + this.report.streamsIn.count++; + this.report.streamsIn.items.push(newReport); + this.stringifyReport = JSON.stringify(this.report, null, '\t'); + } else { + const streamOutRemoteInfo = sessionInfo['connections'] + .find(c => c.connectionId === event.connectionId).publishers + .find(p => p.webrtcTagName === event.streamManager.stream.streamId); + + newReport = { + connectionId: event.connectionId, + streamId: event.streamManager.stream.streamId, + state: event.state, + localCandidatePair: { + localCandidate: localCandidatePair.localCandidate, + remoteCandidate: localCandidatePair.remoteCandidate + }, + remoteCandidatePair: { + localCandidate: streamOutRemoteInfo.localCandidate, + remoteCandidate: streamOutRemoteInfo.remoteCandidate + } + }; + + this.report.streamsOut.count++; + this.report.streamsOut.items.push(newReport); + this.stringifyReport = JSON.stringify(this.report, null, '\t'); + } + }) + .catch(); + }, + error => { } + ); + }*/ + +} diff --git a/openvidu-testapp/src/app/components/test-sessions/test-sessions.component.ts b/openvidu-testapp/src/app/components/test-sessions/test-sessions.component.ts index 75e01114..ad3919a7 100644 --- a/openvidu-testapp/src/app/components/test-sessions/test-sessions.component.ts +++ b/openvidu-testapp/src/app/components/test-sessions/test-sessions.component.ts @@ -44,6 +44,7 @@ export class TestSessionsComponent implements OnInit, OnDestroy { ngOnDestroy() { this.paramsSubscription.unsubscribe(); + this.eventsInfoSubscription.unsubscribe(); } addUser(): void { @@ -92,7 +93,7 @@ export class TestSessionsComponent implements OnInit, OnDestroy { } } - loadScenario(subsPubs: number, pubs: number, subs: number, ): void { + loadScenario(subsPubs: number, pubs: number, subs: number): void { this.users = []; this.loadSubsPubs(subsPubs); this.loadPubs(pubs); diff --git a/openvidu-testapp/src/app/components/users-table/table-video.component.ts b/openvidu-testapp/src/app/components/users-table/table-video.component.ts new file mode 100644 index 00000000..0918bfe0 --- /dev/null +++ b/openvidu-testapp/src/app/components/users-table/table-video.component.ts @@ -0,0 +1,84 @@ +import { Component, Input, AfterViewInit, EventEmitter, Output, DoCheck } from '@angular/core'; +import { StreamManager } from 'openvidu-browser'; + +@Component({ + selector: 'app-table-video', + template: ` +
+ + + {{success() ? 'done' : 'warning'}} +
+ + + `, + styles: ['.icon-div {position: absolute; z-index: 999; left: calc(50% - 60px); padding: 2px 0 0 2px; cursor: pointer}'] +}) +export class TableVideoComponent implements AfterViewInit, DoCheck { + + @Input() streamManager: StreamManagerWrapper; + @Output() readyForReport = new EventEmitter(); + @Output() clickIcon = new EventEmitter(); + + state = {}; + playingTimeout; + + constructor() { } + + ngAfterViewInit() { + this.playingTimeout = setTimeout(() => { + if (!this.state['playing']) { + this.state['timeoutPlaying'] = Date.now(); + this.readyForReport.emit({ + connectionId: this.streamManager.connectionId, + state: this.state, + streamManager: this.streamManager.streamManager + }); + } + }, 10000); + } + + ngDoCheck() { + if ((Object.keys(this.state).length !== Object.keys(this.streamManager.state).length) && + (!this.state['timeoutPlaying'])) { + this.state = Object.assign({}, this.streamManager.state); + if (this.success() || this.fail()) { + clearTimeout(this.playingTimeout); + this.readyForReport.emit({ + connectionId: this.streamManager.connectionId, + state: this.state, + streamManager: this.streamManager.streamManager + }); + } + } + } + + success(): boolean { + return (!!this.state['connected'] && + !!this.state['playing']); + } + + fail(): boolean { + return (!!this.state['errorConnecting'] || + !!this.state['timeoutPlaying']); + } + + emitClickIconEvent(event) { + event.stopPropagation(); + this.clickIcon.emit({ + in: this.streamManager.streamManager.remote, + connectionId: this.streamManager.connectionId, + streamId: this.streamManager.streamManager.stream.streamId + }); + } + +} + +export interface StreamManagerWrapper { + connectionId: string; + streamManager: StreamManager; + state: any; +} diff --git a/openvidu-testapp/src/app/components/users-table/users-table.component.css b/openvidu-testapp/src/app/components/users-table/users-table.component.css new file mode 100644 index 00000000..e588acbc --- /dev/null +++ b/openvidu-testapp/src/app/components/users-table/users-table.component.css @@ -0,0 +1,28 @@ +table { + width: 100%; +} + +tr { + min-height: 90px; +} + +th { + position: relative; +} + +td { + text-align: center; + position: relative; +} + +.mat-cell { + border-bottom: 1px solid rgba(0, 0, 0, .12); +} + +tr:last-child .mat-cell { + border-bottom: none; +} + +#number-of-streams { + margin-bottom: 28px; +} \ No newline at end of file diff --git a/openvidu-testapp/src/app/components/users-table/users-table.component.html b/openvidu-testapp/src/app/components/users-table/users-table.component.html new file mode 100644 index 00000000..60cfb274 --- /dev/null +++ b/openvidu-testapp/src/app/components/users-table/users-table.component.html @@ -0,0 +1,24 @@ + + + + + + + + + +
+

STREAMS

+

+ OUT +

+

+ IN +

+
+

{{publisher.streamManager.stream.connection.connectionId}} | {{publisher.streamManager.stream.streamId}}

+ +
{{connectionId}} + +
\ No newline at end of file diff --git a/openvidu-testapp/src/app/components/users-table/users-table.component.ts b/openvidu-testapp/src/app/components/users-table/users-table.component.ts new file mode 100644 index 00000000..82f3f978 --- /dev/null +++ b/openvidu-testapp/src/app/components/users-table/users-table.component.ts @@ -0,0 +1,37 @@ +import { Component, Input, EventEmitter, Output } from '@angular/core'; +import { StreamManager } from 'openvidu-browser'; +import { StreamManagerWrapper } from './table-video.component'; + +@Component({ + selector: 'app-users-table', + styleUrls: ['users-table.component.css'], + templateUrl: 'users-table.component.html', +}) +export class UsersTableComponent { + + @Input() numberOfStreams = { out: 0, in: 0 }; + @Input() connections: string[] = []; + @Input() publishers: StreamManagerWrapper[] = []; + @Input() subscribers: { connectionId: string, subs: StreamManagerWrapper[] }[] = []; + + @Output() reportForStream = new EventEmitter(true); + @Output() focusReport = new EventEmitter(); + + getSubscriber(connectionId: string, publisher: StreamManager): StreamManagerWrapper { + const subscribersForConnection = this.subscribers.find(s => s.connectionId === connectionId); + if (!!subscribersForConnection && !!subscribersForConnection.subs) { + return subscribersForConnection.subs.find(sub => { + return (sub.streamManager.stream.connection.connectionId === publisher.stream.connection.connectionId); + }); + } + } + + emitReadyForReport(event: StreamManagerWrapper) { + this.reportForStream.emit(event); + } + + emitFocusOnReport(event) { + this.focusReport.emit(event); + } + +} diff --git a/openvidu-testapp/src/app/components/video/ov-video.component.ts b/openvidu-testapp/src/app/components/video/ov-video.component.ts index 99639c32..f2004fb4 100644 --- a/openvidu-testapp/src/app/components/video/ov-video.component.ts +++ b/openvidu-testapp/src/app/components/video/ov-video.component.ts @@ -1,18 +1,28 @@ -import { Component, Input, ViewChild, ElementRef, AfterViewInit } from '@angular/core'; +import { Component, Input, ViewChild, ElementRef, OnInit, AfterViewInit } from '@angular/core'; +import { DomSanitizer, SafeStyle } from '@angular/platform-browser'; import { StreamManager } from 'openvidu-browser'; @Component({ selector: 'app-ov-video', - template: '' + template: '' }) -export class OpenViduVideoComponent implements AfterViewInit { +export class OpenViduVideoComponent implements OnInit, AfterViewInit { @ViewChild('videoElement') elementRef: ElementRef; @Input() poster = ''; + @Input() attrstyle = ''; + + sanitizedStyle: SafeStyle; _streamManager: StreamManager; + constructor(private sanitizer: DomSanitizer) { } + + ngOnInit() { + this.sanitizedStyle = this.sanitizer.bypassSecurityTrustStyle(this.attrstyle); + } + ngAfterViewInit() { this._streamManager.addVideoElement(this.elementRef.nativeElement); } diff --git a/openvidu-testapp/src/app/components/video/video.component.css b/openvidu-testapp/src/app/components/video/video.component.css index 0eed51fb..d5817619 100644 --- a/openvidu-testapp/src/app/components/video/video.component.css +++ b/openvidu-testapp/src/app/components/video/video.component.css @@ -1,6 +1,7 @@ app-ov-video { float: left; height: 90px; + width: 120px; } .data-node { diff --git a/openvidu-testapp/src/app/components/video/video.component.html b/openvidu-testapp/src/app/components/video/video.component.html index 7ebcbe15..3c1099da 100644 --- a/openvidu-testapp/src/app/components/video/video.component.html +++ b/openvidu-testapp/src/app/components/video/video.component.html @@ -1,5 +1,5 @@
- +