mirror of https://github.com/OpenVidu/openvidu.git
openvidu-testapp refactoring to StreamManager openvidu-brwoser API
parent
6684ff414c
commit
0315a75187
|
@ -20,7 +20,8 @@
|
||||||
"prefix": "app",
|
"prefix": "app",
|
||||||
"styles": [
|
"styles": [
|
||||||
"styles.css",
|
"styles.css",
|
||||||
"openvidu-theme.scss"
|
"openvidu-theme.scss",
|
||||||
|
"material-icons.css"
|
||||||
],
|
],
|
||||||
"scripts": [],
|
"scripts": [],
|
||||||
"environmentSource": "environments/environment.ts",
|
"environmentSource": "environments/environment.ts",
|
||||||
|
|
|
@ -10,6 +10,8 @@ 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 { VideoComponent } from './components/video/video.component';
|
||||||
|
import { OpenViduVideoComponent } from './components/video/ov-video.component';
|
||||||
import { ExtensionDialogComponent } from './components/dialogs/extension-dialog.component';
|
import { ExtensionDialogComponent } from './components/dialogs/extension-dialog.component';
|
||||||
import { LocalRecordingDialogComponent } from './components/dialogs/local-recording-dialog.component';
|
import { LocalRecordingDialogComponent } from './components/dialogs/local-recording-dialog.component';
|
||||||
|
|
||||||
|
@ -19,16 +21,20 @@ 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 { SessionPropertiesDialogComponent } from './components/dialogs/session-properties-dialog.component';
|
||||||
import { SessionApiDialogComponent } from './components/dialogs/session-api-dialog.component';
|
import { SessionApiDialogComponent } from './components/dialogs/session-api-dialog.component';
|
||||||
|
import { EventsDialogComponent } from './components/dialogs/events-dialog.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
OpenviduInstanceComponent,
|
OpenviduInstanceComponent,
|
||||||
|
VideoComponent,
|
||||||
|
OpenViduVideoComponent,
|
||||||
TestSessionsComponent,
|
TestSessionsComponent,
|
||||||
TestApirestComponent,
|
TestApirestComponent,
|
||||||
ExtensionDialogComponent,
|
ExtensionDialogComponent,
|
||||||
SessionPropertiesDialogComponent,
|
SessionPropertiesDialogComponent,
|
||||||
SessionApiDialogComponent,
|
SessionApiDialogComponent,
|
||||||
|
EventsDialogComponent,
|
||||||
LocalRecordingDialogComponent
|
LocalRecordingDialogComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -49,6 +55,7 @@ import { SessionApiDialogComponent } from './components/dialogs/session-api-dial
|
||||||
ExtensionDialogComponent,
|
ExtensionDialogComponent,
|
||||||
SessionPropertiesDialogComponent,
|
SessionPropertiesDialogComponent,
|
||||||
SessionApiDialogComponent,
|
SessionApiDialogComponent,
|
||||||
|
EventsDialogComponent,
|
||||||
LocalRecordingDialogComponent
|
LocalRecordingDialogComponent
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-events-dialog',
|
||||||
|
template: `
|
||||||
|
<h2 mat-dialog-title>{{target}} events</h2>
|
||||||
|
<mat-dialog-content>
|
||||||
|
<mat-slide-toggle [(ngModel)]="checkAll" (change)="updateAll()" [color]="'warn'"><i>ALL</i></mat-slide-toggle>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
<mat-slide-toggle *ngFor="let event of eventNamesArray()"
|
||||||
|
[(ngModel)]="eventCollection[event]"
|
||||||
|
[color]="'warn'">{{event}}
|
||||||
|
</mat-slide-toggle>
|
||||||
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions>
|
||||||
|
<button mat-button id="close-dialog-btn" [mat-dialog-close]="eventCollection">CLOSE</button>
|
||||||
|
</mat-dialog-actions>
|
||||||
|
`,
|
||||||
|
styles: [
|
||||||
|
'mat-dialog-content { display: inline; }',
|
||||||
|
'mat-divider { margin-top: 5px; margin-bottom: 5px }'
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class EventsDialogComponent {
|
||||||
|
|
||||||
|
target = '';
|
||||||
|
checkAll = true;
|
||||||
|
eventCollection: any = {};
|
||||||
|
|
||||||
|
constructor(public dialogRef: MatDialogRef<EventsDialogComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data) {
|
||||||
|
this.target = data.target;
|
||||||
|
this.eventCollection = data.eventCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAll() {
|
||||||
|
Object.keys(this.eventCollection).forEach(key => {
|
||||||
|
this.eventCollection[key] = this.checkAll;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
eventNamesArray(): String[] {
|
||||||
|
return Object.keys(this.eventCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -29,13 +29,13 @@ export class LocalRecordingDialogComponent {
|
||||||
|
|
||||||
public myReference: MatDialogRef<LocalRecordingDialogComponent>;
|
public myReference: MatDialogRef<LocalRecordingDialogComponent>;
|
||||||
|
|
||||||
private recorder: LocalRecorder;
|
recorder: LocalRecorder;
|
||||||
|
|
||||||
private uploading = false;
|
uploading = false;
|
||||||
private endpoint = '';
|
endpoint = '';
|
||||||
private uploadIcon: string;
|
uploadIcon: string;
|
||||||
private iconColor: string;
|
iconColor: string;
|
||||||
private iconClass = '';
|
iconClass = '';
|
||||||
|
|
||||||
constructor(@Inject(MAT_DIALOG_DATA) public data: any) {
|
constructor(@Inject(MAT_DIALOG_DATA) public data: any) {
|
||||||
this.recorder = data.recorder;
|
this.recorder = data.recorder;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Session } from 'openvidu-browser';
|
||||||
import { OpenVidu as OpenViduAPI } from 'openvidu-node-client';
|
import { OpenVidu as OpenViduAPI } from 'openvidu-node-client';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-session-properties-dialog',
|
selector: 'app-session-api-dialog',
|
||||||
template: `
|
template: `
|
||||||
<div>
|
<div>
|
||||||
<h2 mat-dialog-title>API REST</h2>
|
<h2 mat-dialog-title>API REST</h2>
|
||||||
|
|
|
@ -34,7 +34,7 @@ mat-card.session-card {
|
||||||
|
|
||||||
.inner-card {
|
.inner-card {
|
||||||
border: 1px solid #e1e1e1;
|
border: 1px solid #e1e1e1;
|
||||||
padding: 10px 15px 10px 15px;
|
padding: 10px 3px 10px 10px;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
|
@ -138,19 +138,25 @@ mat-expansion-panel-header {
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-icon-custom {
|
.mat-icon-custom {
|
||||||
width: 29px;
|
width: 24px;
|
||||||
height: 29px;
|
height: 24px;
|
||||||
line-height: 18px;
|
line-height: 17px;
|
||||||
|
margin-bottom: -4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-icon-custom-ic {
|
.mat-icon-custom-ic {
|
||||||
width: 20px;
|
width: 18px;
|
||||||
height: 20px;
|
height: 18px;
|
||||||
font-size: 20px;
|
font-size: 18px;
|
||||||
line-height: 20px;
|
line-height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.session-btns-div {
|
.session-btns-div {
|
||||||
margin-top: -14px;
|
margin-top: -14px;
|
||||||
margin-right: -14px;
|
margin-right: -14px;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.publisher-btns-div {
|
||||||
|
margin-top: -7px;
|
||||||
}
|
}
|
|
@ -8,20 +8,25 @@
|
||||||
|
|
||||||
<div fxLayout="row">
|
<div fxLayout="row">
|
||||||
<mat-form-field style="margin-right: 10px">
|
<mat-form-field style="margin-right: 10px">
|
||||||
<input matInput placeholder="Session name" id="session-name-input" name="sessionName" [(ngModel)]="sessionName" [disabled]="session">
|
<input matInput placeholder="Session name" [id]="'session-name-input-' + index" name="sessionName" [(ngModel)]="sessionName"
|
||||||
|
[disabled]="session">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input matInput placeholder="Client data" id="client-data-input" name="clientData" [(ngModel)]="clientData" [disabled]="session">
|
<input matInput placeholder="Client data" [id]="'client-data-input-'+ index" name="clientData" [(ngModel)]="clientData" [disabled]="session">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div fxLayout="column" class="session-btns-div">
|
<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">
|
<button mat-icon-button title="Session properties" [id]="'session-settings-btn-' + index" class="mat-icon-custom" (click)="openSessionPropertiesDialog()"
|
||||||
|
[disabled]="session">
|
||||||
<mat-icon class="mat-icon-custom-ic" aria-label="Session properties button">settings</mat-icon>
|
<mat-icon class="mat-icon-custom-ic" aria-label="Session properties button">settings</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button mat-icon-button title="Session API" id="session-api-btn" class="mat-icon-custom" (click)="openSessionApiDialog()">
|
<button mat-icon-button title="Session API" [id]="'session-api-btn-' + index" class="mat-icon-custom" (click)="openSessionApiDialog()">
|
||||||
<mat-icon class="mat-icon-custom-ic" aria-label="Session API button">cloud_circle</mat-icon>
|
<mat-icon class="mat-icon-custom-ic" aria-label="Session API button">cloud_circle</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
<button mat-icon-button title="Session events" [id]="'session-events-btn-' + index" class="mat-icon-custom" (click)="openSessionEventsDialog()">
|
||||||
|
<mat-icon class="mat-icon-custom-ic" aria-label="Session events button">notifications</mat-icon>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -36,7 +41,7 @@
|
||||||
|
|
||||||
<div class="inner-card" fxLayout="row" fxLayoutAlign="start start">
|
<div class="inner-card" fxLayout="row" fxLayoutAlign="start start">
|
||||||
|
|
||||||
<div fxFlex="60">
|
<div fxFlex="55">
|
||||||
<div>
|
<div>
|
||||||
<h4>Send</h4>
|
<h4>Send</h4>
|
||||||
<div>
|
<div>
|
||||||
|
@ -57,7 +62,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="40">
|
<div fxFlex="35">
|
||||||
<mat-radio-group [(ngModel)]="optionsVideo" [disabled]="session || disableRadioButtons" [ngModelOptions]="{standalone: true}">
|
<mat-radio-group [(ngModel)]="optionsVideo" [disabled]="session || disableRadioButtons" [ngModelOptions]="{standalone: true}">
|
||||||
<div>
|
<div>
|
||||||
<mat-radio-button class="video-radio" value="video" [checked]="checkRadioVideo && optionsVideo==='video'">Video</mat-radio-button>
|
<mat-radio-button class="video-radio" value="video" [checked]="checkRadioVideo && optionsVideo==='video'">Video</mat-radio-button>
|
||||||
|
@ -71,6 +76,19 @@
|
||||||
<br>to remote</mat-checkbox>
|
<br>to remote</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div fxFlex="10">
|
||||||
|
<div fxLayout="column" class="publisher-btns-div">
|
||||||
|
<button mat-icon-button title="Publisher properties" [id]="'session-settings-btn-' + index" class="mat-icon-custom" (click)="advancedPublisherOptions()"
|
||||||
|
[disabled]="(!sendAudio && !sendVideo) || !publishTo">
|
||||||
|
<mat-icon class="mat-icon-custom-ic" aria-label="Session properties button">settings</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button title="Add new publisher to running session" [id]="'session-api-btn-' + index" class="mat-icon-custom" (click)="addNewPublisher()"
|
||||||
|
[disabled]="!session || ((!sendAudio && !sendVideo) || !publishTo)">
|
||||||
|
<mat-icon class="mat-icon-custom-ic" aria-label="Session API button">add_circle</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
@ -85,21 +103,9 @@
|
||||||
<div class="session-card-inner">
|
<div class="session-card-inner">
|
||||||
<div class="session-title">{{sessionName}}</div>
|
<div class="session-title">{{sessionName}}</div>
|
||||||
<div class="session-actions">
|
<div class="session-actions">
|
||||||
<button class="change-publisher-btn" *ngIf="publishTo" (click)="changePublisher()" title="Change publisher">
|
|
||||||
<mat-icon aria-label="Change publisher button">switch_video</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button class="publish-btn" *ngIf="publishTo" (click)="publishUnpublish()" title="Publish/Unpublish">
|
|
||||||
<mat-icon aria-label="Publish Unpublish button">{{publishIcon}}</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button class="message-btn" (click)="sendMessage()" title="Broadcast message">
|
<button class="message-btn" (click)="sendMessage()" title="Broadcast message">
|
||||||
<mat-icon aria-label="Send message button" style="font-size: 20px">chat</mat-icon>
|
<mat-icon aria-label="Send message button" style="font-size: 20px">chat</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button class="video-btn" *ngIf="publishTo && sendVideoChange" (click)="toggleVideo()" title="Mute/Unmute video">
|
|
||||||
<mat-icon aria-label="Mute video button">{{videoIcon}}</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button class="audio-btn" *ngIf="publishTo && sendAudioChange" (click)="toggleAudio()" title="Mute/Unmute audio">
|
|
||||||
<mat-icon aria-label="Mute audio button">{{audioIcon}}</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button class="leave-btn" (click)="leaveSession()" title="Leave session">
|
<button class="leave-btn" (click)="leaveSession()" title="Leave session">
|
||||||
<mat-icon aria-label="Leave button">clear</mat-icon>
|
<mat-icon aria-label="Leave button">clear</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
@ -123,6 +129,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div [attr.id]="'remote-vid-' + session.connection.connectionId" fxFlex="240px" class="video-container">
|
<div [attr.id]="'remote-vid-' + session.connection.connectionId" fxFlex="240px" class="video-container">
|
||||||
<div [attr.id]="'local-vid-' + session.connection.connectionId"></div>
|
<div [attr.id]="'local-vid-' + session.connection.connectionId"></div>
|
||||||
|
<app-video *ngIf="this.publisher" [streamManager]="this.publisher" [OV]="OV" (updateEventListInParent)="udpateEventFromChild($event)">
|
||||||
|
</app-video>
|
||||||
|
<app-video *ngFor="let subscriber of this.subscribers" [streamManager]="subscriber" [OV]="OV" (updateEventListInParent)="udpateEventFromChild($event)" (reSubbed)="updateSubscriberFromChild($event)">
|
||||||
|
</app-video>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { Subscription } from 'rxjs/Subscription';
|
||||||
import {
|
import {
|
||||||
OpenVidu, Session, Subscriber, Publisher, Stream, Connection,
|
OpenVidu, Session, Subscriber, Publisher, Stream, Connection,
|
||||||
LocalRecorder, VideoInsertMode, StreamEvent, ConnectionEvent,
|
LocalRecorder, VideoInsertMode, StreamEvent, ConnectionEvent,
|
||||||
SessionDisconnectedEvent, SignalEvent, RecordingEvent, VideoElementEvent
|
SessionDisconnectedEvent, SignalEvent, RecordingEvent, VideoElementEvent, PublisherSpeakingEvent, StreamManagerEvent, StreamManager
|
||||||
} from 'openvidu-browser';
|
} from 'openvidu-browser';
|
||||||
import {
|
import {
|
||||||
OpenVidu as OpenViduAPI,
|
OpenVidu as OpenViduAPI,
|
||||||
|
@ -22,10 +22,10 @@ import { ExtensionDialogComponent } from '../dialogs/extension-dialog.component'
|
||||||
import { LocalRecordingDialogComponent } from '../dialogs/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 { EventsDialogComponent } from '../dialogs/events-dialog.component';
|
||||||
import { SessionPropertiesDialogComponent } from '../dialogs/session-properties-dialog.component';
|
import { SessionPropertiesDialogComponent } from '../dialogs/session-properties-dialog.component';
|
||||||
import { SessionApiDialogComponent } from '../dialogs/session-api-dialog.component';
|
import { SessionApiDialogComponent } from '../dialogs/session-api-dialog.component';
|
||||||
|
|
||||||
declare var $: any;
|
|
||||||
|
|
||||||
export interface SessionConf {
|
export interface SessionConf {
|
||||||
subscribeTo: boolean;
|
subscribeTo: boolean;
|
||||||
|
@ -56,6 +56,9 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
@Input()
|
@Input()
|
||||||
sessionConf: SessionConf;
|
sessionConf: SessionConf;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
index: number;
|
||||||
|
|
||||||
// Session join data
|
// Session join data
|
||||||
clientData: string;
|
clientData: string;
|
||||||
sessionName: string;
|
sessionName: string;
|
||||||
|
@ -91,7 +94,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
OV: OpenVidu;
|
OV: OpenVidu;
|
||||||
session: Session;
|
session: Session;
|
||||||
publisher: Publisher;
|
publisher: Publisher;
|
||||||
subscribers = {};
|
subscribers: Subscriber[] = [];
|
||||||
|
|
||||||
// OpenVidu Node Client objects
|
// OpenVidu Node Client objects
|
||||||
sessionProperties: SessionPropertiesAPI = {
|
sessionProperties: SessionPropertiesAPI = {
|
||||||
|
@ -102,17 +105,18 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
customSessionId: ''
|
customSessionId: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
// Session audio and video status
|
sessionEvents = {
|
||||||
audioMuted = false;
|
connectionCreated: true,
|
||||||
videoMuted = false;
|
connectionDestroyed: true,
|
||||||
unpublished = false;
|
sessionDisconnected: true,
|
||||||
publisherChanged = false;
|
streamCreated: true,
|
||||||
audioIcon = 'mic';
|
streamDestroyed: true,
|
||||||
videoIcon = 'videocam';
|
recordingStarted: true,
|
||||||
publishIcon = 'stop';
|
recordingStopped: true,
|
||||||
|
signal: true,
|
||||||
sendAudioChange: boolean;
|
publisherStartSpeaking: false,
|
||||||
sendVideoChange: boolean;
|
publisherStopSpeaking: false
|
||||||
|
};
|
||||||
|
|
||||||
events: OpenViduEvent[] = [];
|
events: OpenViduEvent[] = [];
|
||||||
|
|
||||||
|
@ -127,8 +131,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
private changeDetector: ChangeDetectorRef,
|
private changeDetector: ChangeDetectorRef,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private recordDialog: MatDialog,
|
private recordDialog: MatDialog,
|
||||||
private testFeedService: TestFeedService,
|
private testFeedService: TestFeedService
|
||||||
private muteSubscribersService: MuteSubscribersService,
|
|
||||||
) {
|
) {
|
||||||
this.generateSessionInfo();
|
this.generateSessionInfo();
|
||||||
}
|
}
|
||||||
|
@ -147,13 +150,6 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
if (this.sessionConf.startSession) {
|
if (this.sessionConf.startSession) {
|
||||||
this.joinSession();
|
this.joinSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.muteSubscribersSubscription = this.muteSubscribersService.mutedEvent$.subscribe(
|
|
||||||
muteOrUnmute => {
|
|
||||||
Object.keys(this.subscribers).forEach((key) => {
|
|
||||||
this.subscribers[key].videoElement.muted = muteOrUnmute;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
|
@ -166,7 +162,6 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
if (!!this.muteSubscribersSubscription) { this.muteSubscribersSubscription.unsubscribe(); }
|
|
||||||
this.leaveSession();
|
this.leaveSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,24 +194,24 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
|
|
||||||
this.session = this.OV.initSession();
|
this.session = this.OV.initSession();
|
||||||
|
|
||||||
this.addSessionEvents(this.session);
|
this.updateSessionEvents({
|
||||||
|
connectionCreated: false,
|
||||||
|
connectionDestroyed: false,
|
||||||
|
sessionDisconnected: false,
|
||||||
|
streamCreated: false,
|
||||||
|
streamDestroyed: false,
|
||||||
|
recordingStarted: false,
|
||||||
|
recordingStopped: false,
|
||||||
|
signal: false,
|
||||||
|
publisherStartSpeaking: true,
|
||||||
|
publisherStopSpeaking: true
|
||||||
|
}, true);
|
||||||
|
|
||||||
this.session.connect(token, this.clientData)
|
this.session.connect(token, this.clientData)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.changeDetector.detectChanges();
|
this.changeDetector.detectChanges();
|
||||||
|
|
||||||
if (this.publishTo) {
|
if (this.publishTo) {
|
||||||
|
|
||||||
this.audioMuted = !this.activeAudio;
|
|
||||||
this.videoMuted = !this.activeVideo;
|
|
||||||
this.unpublished = false;
|
|
||||||
this.updateAudioIcon();
|
|
||||||
this.updateVideoIcon();
|
|
||||||
this.updatePublishIcon();
|
|
||||||
|
|
||||||
this.sendAudioChange = this.sendAudio;
|
|
||||||
this.sendVideoChange = this.sendVideo;
|
|
||||||
|
|
||||||
// this.asyncInitPublisher();
|
// this.asyncInitPublisher();
|
||||||
this.syncInitPublisher();
|
this.syncInitPublisher();
|
||||||
}
|
}
|
||||||
|
@ -226,113 +221,14 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private leaveSession(): void {
|
private leaveSession(): void {
|
||||||
if (!!this.publisherRecorder) {
|
|
||||||
this.restartPublisherRecord();
|
|
||||||
}
|
|
||||||
Object.keys(this.subscribers).forEach((key) => {
|
|
||||||
if (!!this.subscribers[key].recorder) {
|
|
||||||
this.restartSubscriberRecord(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (this.session) {
|
if (this.session) {
|
||||||
this.session.disconnect();
|
this.session.disconnect();
|
||||||
}
|
}
|
||||||
this.session = null;
|
delete this.session;
|
||||||
this.OV = null;
|
delete this.OV;
|
||||||
}
|
delete this.publisher;
|
||||||
|
this.subscribers = [];
|
||||||
private toggleAudio() {
|
|
||||||
this.publisher.publishAudio(this.audioMuted);
|
|
||||||
this.audioMuted = !this.audioMuted;
|
|
||||||
this.updateAudioIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
private toggleVideo() {
|
|
||||||
this.publisher.publishVideo(this.videoMuted);
|
|
||||||
this.videoMuted = !this.videoMuted;
|
|
||||||
this.updateVideoIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
private updateAudioIcon() {
|
|
||||||
this.audioMuted ? this.audioIcon = 'mic_off' : this.audioIcon = 'mic';
|
|
||||||
}
|
|
||||||
|
|
||||||
private updateVideoIcon() {
|
|
||||||
this.videoMuted ? this.videoIcon = 'videocam_off' : this.videoIcon = 'videocam';
|
|
||||||
}
|
|
||||||
|
|
||||||
private updatePublishIcon() {
|
|
||||||
this.unpublished ? this.publishIcon = 'play_arrow' : this.publishIcon = 'stop';
|
|
||||||
}
|
|
||||||
|
|
||||||
private appendSubscriberData(videoElement: HTMLVideoElement, connection: Connection): void {
|
|
||||||
const dataNode = document.createElement('div');
|
|
||||||
dataNode.className = 'data-node';
|
|
||||||
dataNode.id = 'data-' + this.session.connection.connectionId + '-' + connection.connectionId;
|
|
||||||
dataNode.innerHTML = '<p class="name">' + connection.data + '</p>' +
|
|
||||||
'<button id="sub-btn-' + this.session.connection.connectionId + '-' + connection.connectionId +
|
|
||||||
'" class="sub-btn" title="Subscribe/Unsubscribe"><mat-icon id="sub-icon-' + this.session.connection.connectionId +
|
|
||||||
'-' + connection.connectionId + '" aria-label="Subscribe or unsubscribe" class="mat-icon material-icons" role="img"' +
|
|
||||||
'aria-hidden="true">notifications</mat-icon></button>' +
|
|
||||||
'<button id="sub-video-btn-' + this.session.connection.connectionId + '-' + connection.connectionId +
|
|
||||||
'" class="sub-btn sub-video-btn" title="Subscribe/Unsubscribe Video"><mat-icon id="sub-video-icon-' +
|
|
||||||
this.session.connection.connectionId +
|
|
||||||
'-' + connection.connectionId + '" aria-label="Subscribe or unsubscribe" class="mat-icon material-icons" role="img"' +
|
|
||||||
'aria-hidden="true">videocam</mat-icon></button>' +
|
|
||||||
'<button id="sub-audio-btn-' + this.session.connection.connectionId + '-' + connection.connectionId +
|
|
||||||
'" class="sub-btn sub-audio-btn" title="Subscribe/Unsubscribe Audio"><mat-icon id="sub-audio-icon-' +
|
|
||||||
this.session.connection.connectionId +
|
|
||||||
'-' + connection.connectionId + '" aria-label="Subscribe or unsubscribe" class="mat-icon material-icons" role="img"' +
|
|
||||||
'aria-hidden="true">mic</mat-icon></button>' +
|
|
||||||
'<button id="record-btn-' + this.session.connection.connectionId + '-' + connection.connectionId +
|
|
||||||
'" class="sub-btn rec-btn" title="Record"><mat-icon id="record-icon-' +
|
|
||||||
this.session.connection.connectionId + '-' + connection.connectionId +
|
|
||||||
'" aria-label="Start/Stop recording" class="mat-icon material-icons" role="img"' +
|
|
||||||
'aria-hidden="true">fiber_manual_record</mat-icon></button>' +
|
|
||||||
'<button style="display:none" id="pause-btn-' + this.session.connection.connectionId + '-' + connection.connectionId +
|
|
||||||
'" class="sub-btn rec-btn rec-pause-btn" title="Pause/Resume"><mat-icon id="pause-icon-' +
|
|
||||||
this.session.connection.connectionId + '-' + connection.connectionId +
|
|
||||||
'" aria-label="Pause/Resume recording" class="mat-icon material-icons" role="img"' +
|
|
||||||
'aria-hidden="true">pause</mat-icon></button>';
|
|
||||||
videoElement.parentNode.insertBefore(dataNode, videoElement.nextSibling);
|
|
||||||
document.getElementById('sub-btn-' + this.session.connection.connectionId + '-' + connection.connectionId)
|
|
||||||
.addEventListener('click', this.subUnsubFromSubscriber.bind(this, connection.connectionId));
|
|
||||||
document.getElementById('sub-video-btn-' + this.session.connection.connectionId + '-' + connection.connectionId)
|
|
||||||
.addEventListener('click', this.subUnsubFromSubscriberVideo.bind(this, connection.connectionId));
|
|
||||||
document.getElementById('sub-audio-btn-' + this.session.connection.connectionId + '-' + connection.connectionId)
|
|
||||||
.addEventListener('click', this.subUnsubFromSubscriberAudio.bind(this, connection.connectionId));
|
|
||||||
document.getElementById('record-btn-' + this.session.connection.connectionId + '-' + connection.connectionId)
|
|
||||||
.addEventListener('click', this.recordSubscriber.bind(this, connection.connectionId));
|
|
||||||
document.getElementById('pause-btn-' + this.session.connection.connectionId + '-' + connection.connectionId)
|
|
||||||
.addEventListener('click', this.pauseSubscriber.bind(this, connection.connectionId));
|
|
||||||
}
|
|
||||||
|
|
||||||
private appendPublisherData(videoElement: HTMLVideoElement): void {
|
|
||||||
const dataNode = document.createElement('div');
|
|
||||||
dataNode.className = 'data-node';
|
|
||||||
dataNode.id = 'data-' + this.session.connection.connectionId + '-' + this.session.connection.connectionId;
|
|
||||||
dataNode.innerHTML =
|
|
||||||
'<button id="local-record-btn-' + this.session.connection.connectionId +
|
|
||||||
'" class="sub-btn rec-btn publisher-rec-btn" title="Record"><mat-icon id="local-record-icon-' + this.session.connection.connectionId +
|
|
||||||
'" aria-label="Start/Stop local recording" class="mat-icon material-icons" role="img" aria-hidden="true">' +
|
|
||||||
'fiber_manual_record</mat-icon></button>' +
|
|
||||||
'<button style="display:none" id="local-pause-btn-' + this.session.connection.connectionId +
|
|
||||||
'" class="sub-btn rec-btn publisher-rec-btn publisher-rec-pause-btn" title="Pause/Resume">' +
|
|
||||||
'<mat-icon id="local-pause-icon-' + this.session.connection.connectionId +
|
|
||||||
'" aria-label="Pause/Resume local recording" class="mat-icon material-icons" role="img" aria-hidden="true">' +
|
|
||||||
'pause</mat-icon></button>';
|
|
||||||
videoElement.parentNode.insertBefore(dataNode, videoElement.nextSibling);
|
|
||||||
document.getElementById('local-record-btn-' + this.session.connection.connectionId).addEventListener('click',
|
|
||||||
this.recordPublisher.bind(this));
|
|
||||||
document.getElementById('local-pause-btn-' + this.session.connection.connectionId).addEventListener('click',
|
|
||||||
this.pausePublisher.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
private removeUserData(connectionId: string): void {
|
|
||||||
$('#remote-vid-' + this.session.connection.connectionId)
|
|
||||||
.find('#data-' + this.session.connection.connectionId + '-' + connectionId).remove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateEventList(event: string, content: string) {
|
private updateEventList(event: string, content: string) {
|
||||||
|
@ -433,432 +329,122 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
// this.initGrayVideo();
|
// this.initGrayVideo();
|
||||||
}
|
}
|
||||||
|
|
||||||
recordPublisher(): void {
|
updateSessionEvents(oldValues, firstTime) {
|
||||||
if (!this.publisherRecording) {
|
|
||||||
this.publisherRecorder = this.OV.initLocalRecorder(this.publisher.stream);
|
|
||||||
this.publisherRecorder.record();
|
|
||||||
this.publisherRecording = true;
|
|
||||||
document.getElementById('local-record-icon-' + this.session.connection.connectionId).innerHTML = 'stop';
|
|
||||||
document.getElementById('local-pause-btn-' + this.session.connection.connectionId).style.display = 'block';
|
|
||||||
} else {
|
|
||||||
this.publisherRecorder.stop()
|
|
||||||
.then(() => {
|
|
||||||
let dialogRef: MatDialogRef<LocalRecordingDialogComponent>;
|
|
||||||
dialogRef = this.recordDialog.open(LocalRecordingDialogComponent, {
|
|
||||||
disableClose: true,
|
|
||||||
data: {
|
|
||||||
recorder: this.publisherRecorder
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dialogRef.componentInstance.myReference = dialogRef;
|
|
||||||
|
|
||||||
dialogRef.afterOpen().subscribe(() => {
|
|
||||||
this.afterOpenPreview(this.publisherRecorder);
|
|
||||||
});
|
|
||||||
dialogRef.afterClosed().subscribe(() => {
|
|
||||||
this.afterClosePreview();
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error('Error stopping LocalRecorder: ' + error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pausePublisher(): void {
|
|
||||||
if (!this.publisherPaused) {
|
|
||||||
this.publisherRecorder.pause();
|
|
||||||
document.getElementById('local-pause-icon-' + this.session.connection.connectionId).innerHTML = 'play_arrow';
|
|
||||||
} else {
|
|
||||||
this.publisherRecorder.resume();
|
|
||||||
document.getElementById('local-pause-icon-' + this.session.connection.connectionId).innerHTML = 'pause';
|
|
||||||
}
|
|
||||||
this.publisherPaused = !this.publisherPaused;
|
|
||||||
}
|
|
||||||
|
|
||||||
recordSubscriber(connectionId: string): void {
|
|
||||||
const subscriber: Subscriber = this.subscribers[connectionId].subscriber;
|
|
||||||
const recording = this.subscribers[connectionId].recording;
|
|
||||||
if (!recording) {
|
|
||||||
this.subscribers[connectionId].recorder = this.OV.initLocalRecorder(subscriber.stream);
|
|
||||||
this.subscribers[connectionId].recorder.record();
|
|
||||||
this.subscribers[connectionId].recording = true;
|
|
||||||
document.getElementById('record-icon-' + this.session.connection.connectionId + '-' + connectionId).innerHTML = 'stop';
|
|
||||||
document.getElementById('pause-btn-' + this.session.connection.connectionId + '-' + connectionId).style.display = 'block';
|
|
||||||
} else {
|
|
||||||
this.subscribers[connectionId].recorder.stop()
|
|
||||||
.then(() => {
|
|
||||||
let dialogRef: MatDialogRef<LocalRecordingDialogComponent>;
|
|
||||||
dialogRef = this.recordDialog.open(LocalRecordingDialogComponent, {
|
|
||||||
disableClose: true,
|
|
||||||
data: {
|
|
||||||
recorder: this.subscribers[connectionId].recorder
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dialogRef.componentInstance.myReference = dialogRef;
|
|
||||||
|
|
||||||
dialogRef.afterOpen().subscribe(() => {
|
|
||||||
this.afterOpenPreview(this.subscribers[connectionId].recorder);
|
|
||||||
});
|
|
||||||
dialogRef.afterClosed().subscribe(() => {
|
|
||||||
this.afterClosePreview(connectionId);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error('Error stopping LocalRecorder: ' + error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pauseSubscriber(connectionId: string): void {
|
|
||||||
const subscriber: Subscriber = this.subscribers[connectionId].subscriber;
|
|
||||||
const subscriberPaused = this.subscribers[connectionId].paused;
|
|
||||||
if (!subscriberPaused) {
|
|
||||||
this.subscribers[connectionId].recorder.pause();
|
|
||||||
document.getElementById('pause-icon-' + this.session.connection.connectionId + '-' + connectionId).innerHTML = 'play_arrow';
|
|
||||||
} else {
|
|
||||||
this.subscribers[connectionId].recorder.resume();
|
|
||||||
document.getElementById('pause-icon-' + this.session.connection.connectionId + '-' + connectionId).innerHTML = 'pause';
|
|
||||||
}
|
|
||||||
this.subscribers[connectionId].paused = !this.subscribers[connectionId].paused;
|
|
||||||
}
|
|
||||||
|
|
||||||
publishUnpublish(): void {
|
|
||||||
if (this.unpublished) {
|
|
||||||
this.session.publish(this.publisher)
|
|
||||||
.then(() => {
|
|
||||||
console.log(this.publisher);
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
console.error(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.session.unpublish(this.publisher);
|
|
||||||
this.removeUserData(this.session.connection.connectionId);
|
|
||||||
this.restartPublisherRecord();
|
|
||||||
}
|
|
||||||
this.unpublished = !this.unpublished;
|
|
||||||
this.updatePublishIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
changePublisher() {
|
|
||||||
let screenChange;
|
|
||||||
if (!this.publisherChanged) {
|
|
||||||
if (this.sendAudio && !this.sendVideo) {
|
|
||||||
this.sendAudioChange = false;
|
|
||||||
this.sendVideoChange = true;
|
|
||||||
screenChange = false;
|
|
||||||
} else if (!this.sendAudio && this.sendVideo) {
|
|
||||||
this.sendAudioChange = true;
|
|
||||||
this.sendVideoChange = false;
|
|
||||||
} else if (this.sendAudio && this.sendVideo && this.optionsVideo === 'video') {
|
|
||||||
this.sendAudioChange = false;
|
|
||||||
this.sendVideoChange = true;
|
|
||||||
screenChange = true;
|
|
||||||
} else if (this.sendAudio && this.sendVideo && this.optionsVideo === 'screen') {
|
|
||||||
this.sendAudioChange = false;
|
|
||||||
this.sendVideoChange = true;
|
|
||||||
screenChange = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.sendAudioChange = this.sendAudio;
|
|
||||||
this.sendVideoChange = this.sendVideo;
|
|
||||||
screenChange = this.optionsVideo === 'screen' ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.audioMuted = false;
|
|
||||||
this.videoMuted = false;
|
|
||||||
this.unpublished = false;
|
|
||||||
this.updateAudioIcon();
|
|
||||||
this.updateVideoIcon();
|
|
||||||
this.updatePublishIcon();
|
|
||||||
|
|
||||||
const otherPublisher = this.OV.initPublisher(
|
|
||||||
'local-vid-' + this.session.connection.connectionId,
|
|
||||||
{
|
|
||||||
audioSource: this.sendAudioChange ? undefined : false,
|
|
||||||
videoSource: this.sendVideoChange ? (screenChange ? 'screen' : undefined) : false,
|
|
||||||
publishAudio: (!this.publisherChanged) ? true : !this.audioMuted,
|
|
||||||
publishVideo: (!this.publisherChanged) ? true : !this.videoMuted,
|
|
||||||
resolution: '640x480',
|
|
||||||
frameRate: 30,
|
|
||||||
insertMode: VideoInsertMode.APPEND
|
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
if (err) {
|
|
||||||
console.warn(err);
|
|
||||||
this.openviduError = err;
|
|
||||||
if (err.name === 'SCREEN_EXTENSION_NOT_INSTALLED') {
|
|
||||||
this.dialog.open(ExtensionDialogComponent, {
|
|
||||||
data: { url: err.message },
|
|
||||||
disableClose: true,
|
|
||||||
width: '250px'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.addPublisherEvents(otherPublisher);
|
|
||||||
|
|
||||||
otherPublisher.once('accessAllowed', () => {
|
|
||||||
if (!this.unpublished) {
|
|
||||||
this.session.unpublish(this.publisher);
|
|
||||||
this.publisher = otherPublisher;
|
|
||||||
this.removeUserData(this.session.connection.connectionId);
|
|
||||||
this.restartPublisherRecord();
|
|
||||||
}
|
|
||||||
this.session.publish(otherPublisher);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.publisherChanged = !this.publisherChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
subUnsubFromSubscriber(connectionId: string) {
|
|
||||||
let subscriber: Subscriber = this.subscribers[connectionId].subscriber;
|
|
||||||
if (this.subscribers[connectionId].subbed) {
|
|
||||||
this.session.unsubscribe(subscriber);
|
|
||||||
this.restartSubscriberRecord(connectionId);
|
|
||||||
document.getElementById('data-' + this.session.connection.connectionId + '-' + connectionId).style.marginLeft = '0';
|
|
||||||
document.getElementById('sub-icon-' + this.session.connection.connectionId + '-' + connectionId).innerHTML = 'notifications_off';
|
|
||||||
document.getElementById('record-btn-' + this.session.connection.connectionId + '-' + connectionId).remove();
|
|
||||||
document.getElementById('pause-btn-' + this.session.connection.connectionId + '-' + connectionId).remove();
|
|
||||||
document.getElementById('sub-video-btn-' + this.session.connection.connectionId + '-' + connectionId).remove();
|
|
||||||
document.getElementById('sub-audio-btn-' + this.session.connection.connectionId + '-' + connectionId).remove();
|
|
||||||
this.subscribers[connectionId].subbedVideo = false;
|
|
||||||
this.subscribers[connectionId].subbedAudio = false;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
|
|
||||||
this.session.subscribeAsync(subscriber.stream, 'remote-vid-' + this.session.connection.connectionId)
|
|
||||||
.then(sub => {
|
|
||||||
subscriber = sub;
|
|
||||||
this.subscribers[connectionId].subscriber = subscriber;
|
|
||||||
subscriber.on('videoElementCreated', (e: VideoElementEvent) => {
|
|
||||||
if (!subscriber.stream.hasVideo) {
|
|
||||||
$(e.element).css({ 'background-color': '#4d4d4d' });
|
|
||||||
$(e.element).attr('poster', 'assets/images/volume.png');
|
|
||||||
}
|
|
||||||
this.subscribers[connectionId].videoElement = e.element;
|
|
||||||
this.updateEventList('videoElementCreated', e.element.id);
|
|
||||||
});
|
|
||||||
subscriber.on('videoPlaying', (e: VideoElementEvent) => {
|
|
||||||
this.removeUserData(connectionId);
|
|
||||||
this.appendSubscriberData(e.element, subscriber.stream.connection);
|
|
||||||
this.updateEventList('videoPlaying', e.element.id);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/*subscriber = this.session.subscribe(subscriber.stream, 'remote-vid-' + this.session.connection.connectionId);
|
|
||||||
this.subscribers[connectionId].subscriber = subscriber;
|
|
||||||
subscriber.on('videoElementCreated', (e) => {
|
|
||||||
if (!subscriber.stream.hasVideo) {
|
|
||||||
$(e.element).css({ 'background-color': '#4d4d4d' });
|
|
||||||
$(e.element).attr('poster', 'assets/images/volume.png');
|
|
||||||
}
|
|
||||||
this.subscribers[connectionId].videoElement = e.element;
|
|
||||||
this.updateEventList('videoElementCreated', e.element.id);
|
|
||||||
});
|
|
||||||
subscriber.on('videoPlaying', (e) => {
|
|
||||||
this.removeUserData(connectionId);
|
|
||||||
this.appendSubscriberData(e.element, subscriber.stream.connection);
|
|
||||||
this.updateEventList('videoPlaying', e.element.id);
|
|
||||||
});*/
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
this.subscribers[connectionId].subbed = !this.subscribers[connectionId].subbed;
|
|
||||||
}
|
|
||||||
|
|
||||||
subUnsubFromSubscriberVideo(connectionId: string) {
|
|
||||||
this.subscribers[connectionId].subscriber.subscribeToVideo(!!this.subscribers[connectionId].subbedVideo);
|
|
||||||
this.subscribers[connectionId].subbedVideo = !this.subscribers[connectionId].subbedVideo;
|
|
||||||
document.getElementById('sub-video-icon-' + this.session.connection.connectionId + '-' + connectionId).innerHTML =
|
|
||||||
this.subscribers[connectionId].subbedVideo ? 'videocam_off' : 'videocam';
|
|
||||||
}
|
|
||||||
|
|
||||||
subUnsubFromSubscriberAudio(connectionId: string) {
|
|
||||||
this.subscribers[connectionId].subscriber.subscribeToAudio(!!this.subscribers[connectionId].subbedAudio);
|
|
||||||
this.subscribers[connectionId].subbedAudio = !this.subscribers[connectionId].subbedAudio;
|
|
||||||
document.getElementById('sub-audio-icon-' + this.session.connection.connectionId + '-' + connectionId).innerHTML =
|
|
||||||
this.subscribers[connectionId].subbedAudio ? 'mic_off' : 'mic';
|
|
||||||
}
|
|
||||||
|
|
||||||
addSessionEvents(session: Session) {
|
|
||||||
session.on('streamCreated', (event: StreamEvent) => {
|
|
||||||
|
|
||||||
|
if (this.sessionEvents.streamCreated !== oldValues.streamCreated || firstTime) {
|
||||||
|
this.session.off('streamCreated');
|
||||||
|
if (this.sessionEvents.streamCreated) {
|
||||||
|
this.session.on('streamCreated', (event: StreamEvent) => {
|
||||||
this.changeDetector.detectChanges();
|
this.changeDetector.detectChanges();
|
||||||
|
|
||||||
if (this.subscribeTo) {
|
if (this.subscribeTo) {
|
||||||
// this.syncSubscribe(session, event);
|
this.syncSubscribe(this.session, event);
|
||||||
this.asyncSubscribe(session, event);
|
|
||||||
}
|
}
|
||||||
this.updateEventList('streamCreated', event.stream.connection.connectionId);
|
this.updateEventList('streamCreated', event.stream.streamId);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
session.on('streamDestroyed', (event: StreamEvent) => {
|
if (this.sessionEvents.streamDestroyed !== oldValues.streamDestroyed || firstTime) {
|
||||||
this.removeUserData(event.stream.connection.connectionId);
|
this.session.off('streamDestroyed');
|
||||||
this.updateEventList('streamDestroyed', event.stream.connection.connectionId);
|
if (this.sessionEvents.streamDestroyed) {
|
||||||
|
this.session.on('streamDestroyed', (event: StreamEvent) => {
|
||||||
|
const index = this.subscribers.indexOf(<Subscriber>event.stream.streamManager);
|
||||||
|
if (index > -1) {
|
||||||
|
this.subscribers.splice(index, 1);
|
||||||
|
}
|
||||||
|
this.updateEventList('streamDestroyed', event.stream.streamId);
|
||||||
});
|
});
|
||||||
session.on('connectionCreated', (event: ConnectionEvent) => {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.sessionEvents.connectionCreated !== oldValues.connectionCreated || firstTime) {
|
||||||
|
this.session.off('connectionCreated');
|
||||||
|
if (this.sessionEvents.connectionCreated) {
|
||||||
|
this.session.on('connectionCreated', (event: ConnectionEvent) => {
|
||||||
this.updateEventList('connectionCreated', event.connection.connectionId);
|
this.updateEventList('connectionCreated', event.connection.connectionId);
|
||||||
});
|
});
|
||||||
session.on('connectionDestroyed', (event: ConnectionEvent) => {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.sessionEvents.connectionDestroyed !== oldValues.connectionDestroyed || firstTime) {
|
||||||
|
this.session.off('connectionDestroyed');
|
||||||
|
if (this.sessionEvents.connectionDestroyed) {
|
||||||
|
this.session.on('connectionDestroyed', (event: ConnectionEvent) => {
|
||||||
|
delete this.subscribers[event.connection.connectionId];
|
||||||
this.updateEventList('connectionDestroyed', event.connection.connectionId);
|
this.updateEventList('connectionDestroyed', event.connection.connectionId);
|
||||||
});
|
});
|
||||||
session.on('sessionDisconnected', (event: SessionDisconnectedEvent) => {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.sessionEvents.sessionDisconnected !== oldValues.sessionDisconnected || firstTime) {
|
||||||
|
this.session.off('sessionDisconnected');
|
||||||
|
if (this.sessionEvents.sessionDisconnected) {
|
||||||
|
this.session.on('sessionDisconnected', (event: SessionDisconnectedEvent) => {
|
||||||
this.updateEventList('sessionDisconnected', 'No data');
|
this.updateEventList('sessionDisconnected', 'No data');
|
||||||
if (event.reason === 'networkDisconnect') {
|
if (event.reason === 'networkDisconnect') {
|
||||||
this.session = null;
|
this.session = null;
|
||||||
this.OV = null;
|
this.OV = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
session.on('signal', (event: SignalEvent) => {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.sessionEvents.signal !== oldValues.signal || firstTime) {
|
||||||
|
this.session.off('signal');
|
||||||
|
if (this.sessionEvents.signal) {
|
||||||
|
this.session.on('signal', (event: SignalEvent) => {
|
||||||
this.updateEventList('signal', event.from.connectionId + '-' + event.data);
|
this.updateEventList('signal', event.from.connectionId + '-' + event.data);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
session.on('recordingStarted', (event: RecordingEvent) => {
|
if (this.sessionEvents.recordingStarted !== oldValues.recordingStarted || firstTime) {
|
||||||
|
this.session.off('recordingStarted');
|
||||||
|
if (this.sessionEvents.recordingStarted) {
|
||||||
|
this.session.on('recordingStarted', (event: RecordingEvent) => {
|
||||||
this.updateEventList('recordingStarted', event.id);
|
this.updateEventList('recordingStarted', event.id);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
session.on('recordingStopped', (event: RecordingEvent) => {
|
if (this.sessionEvents.recordingStopped !== oldValues.recordingStopped || firstTime) {
|
||||||
|
this.session.off('recordingStopped');
|
||||||
|
if (this.sessionEvents.recordingStopped) {
|
||||||
|
this.session.on('recordingStopped', (event: RecordingEvent) => {
|
||||||
this.updateEventList('recordingStopped', event.id);
|
this.updateEventList('recordingStopped', event.id);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
/*session.on('publisherStartSpeaking', (event) => {
|
|
||||||
console.log('Publisher start speaking');
|
|
||||||
});
|
|
||||||
|
|
||||||
session.on('publisherStopSpeaking', (event) => {
|
|
||||||
console.log('Publisher stop speaking');
|
|
||||||
});*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addPublisherEvents(publisher: Publisher) {
|
if (this.sessionEvents.publisherStartSpeaking !== oldValues.publisherStartSpeaking || firstTime) {
|
||||||
publisher.on('videoElementCreated', (event: VideoElementEvent) => {
|
this.session.off('publisherStartSpeaking');
|
||||||
if (this.publishTo &&
|
if (this.sessionEvents.publisherStartSpeaking) {
|
||||||
(!this.sendVideoChange ||
|
this.session.on('publisherStartSpeaking', (event: PublisherSpeakingEvent) => {
|
||||||
this.sendVideoChange &&
|
this.updateEventList('publisherStartSpeaking', event.connection.connectionId);
|
||||||
!(this.optionsVideo !== 'screen') &&
|
|
||||||
this.openviduError &&
|
|
||||||
this.openviduError.name === 'NO_VIDEO_DEVICE')) {
|
|
||||||
$(event.element).css({ 'background-color': '#4d4d4d' });
|
|
||||||
$(event.element).attr('poster', 'assets/images/volume.png');
|
|
||||||
}
|
|
||||||
this.updateEventList('videoElementCreated', event.element.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
publisher.on('accessAllowed', (e) => {
|
|
||||||
this.updateEventList('accessAllowed', '');
|
|
||||||
});
|
|
||||||
|
|
||||||
publisher.on('accessDenied', (e) => {
|
|
||||||
this.updateEventList('accessDenied', '');
|
|
||||||
});
|
|
||||||
|
|
||||||
publisher.on('accessDialogOpened', (e) => {
|
|
||||||
this.updateEventList('accessDialogOpened', '');
|
|
||||||
});
|
|
||||||
|
|
||||||
publisher.on('accessDialogClosed', (e) => {
|
|
||||||
this.updateEventList('accessDialogClosed', '');
|
|
||||||
});
|
|
||||||
|
|
||||||
publisher.on('videoPlaying', (e: VideoElementEvent) => {
|
|
||||||
this.appendPublisherData(e.element);
|
|
||||||
this.updateEventList('videoPlaying', e.element.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
publisher.on('remoteVideoPlaying', (e: VideoElementEvent) => {
|
|
||||||
this.appendPublisherData(e.element);
|
|
||||||
this.updateEventList('remoteVideoPlaying', e.element.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
publisher.on('streamCreated', (e: StreamEvent) => {
|
|
||||||
this.updateEventList('streamCreated', e.stream.connection.connectionId);
|
|
||||||
});
|
|
||||||
|
|
||||||
publisher.on('streamDestroyed', (e: StreamEvent) => {
|
|
||||||
this.updateEventList('streamDestroyed', e.stream.connection.connectionId);
|
|
||||||
});
|
|
||||||
|
|
||||||
publisher.on('videoElementDestroyed', (e: VideoElementEvent) => {
|
|
||||||
this.updateEventList('videoElementDestroyed', '(Publisher)');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private afterOpenPreview(recorder: LocalRecorder): void {
|
|
||||||
this.muteSubscribersService.updateMuted(true);
|
|
||||||
recorder.preview('recorder-preview').controls = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private afterClosePreview(connectionId?: string): void {
|
if (this.sessionEvents.publisherStopSpeaking !== oldValues.publisherStopSpeaking || firstTime) {
|
||||||
this.muteSubscribersService.updateMuted(false);
|
this.session.off('publisherStopSpeaking');
|
||||||
if (!!connectionId) {
|
if (this.sessionEvents.publisherStopSpeaking) {
|
||||||
this.restartSubscriberRecord(connectionId);
|
this.session.on('publisherStopSpeaking', (event: PublisherSpeakingEvent) => {
|
||||||
} else {
|
this.updateEventList('publisherStopSpeaking', event.connection.connectionId);
|
||||||
this.restartPublisherRecord();
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private restartPublisherRecord(): void {
|
|
||||||
if (!!this.session) {
|
|
||||||
let el: HTMLElement = document.getElementById('local-record-icon-' + this.session.connection.connectionId);
|
|
||||||
if (!!el) {
|
|
||||||
el.innerHTML = 'fiber_manual_record';
|
|
||||||
}
|
|
||||||
el = document.getElementById('local-pause-icon-' + this.session.connection.connectionId);
|
|
||||||
if (!!el) {
|
|
||||||
el.innerHTML = 'pause';
|
|
||||||
}
|
|
||||||
el = document.getElementById('local-pause-btn-' + this.session.connection.connectionId);
|
|
||||||
if (!!el) {
|
|
||||||
el.style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.publisherPaused = false;
|
|
||||||
this.publisherRecording = false;
|
|
||||||
if (!!this.publisherRecorder) {
|
|
||||||
this.publisherRecorder.clean();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private restartSubscriberRecord(connectionId: string): void {
|
|
||||||
if (!!this.session) {
|
|
||||||
let el: HTMLElement = document.getElementById('record-icon-' + this.session.connection.connectionId + '-' + connectionId);
|
|
||||||
if (!!el) {
|
|
||||||
el.innerHTML = 'fiber_manual_record';
|
|
||||||
}
|
|
||||||
el = document.getElementById('pause-icon-' + this.session.connection.connectionId + '-' + connectionId);
|
|
||||||
if (!!el) {
|
|
||||||
el.innerHTML = 'pause';
|
|
||||||
}
|
|
||||||
el = document.getElementById('pause-btn-' + this.session.connection.connectionId + '-' + connectionId);
|
|
||||||
if (!!el) {
|
|
||||||
el.style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.subscribers[connectionId].recording = false;
|
|
||||||
this.subscribers[connectionId].paused = false;
|
|
||||||
|
|
||||||
if (!!this.subscribers[connectionId].recorder) {
|
|
||||||
this.subscribers[connectionId].recorder.clean();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
syncInitPublisher() {
|
syncInitPublisher() {
|
||||||
this.publisher = this.OV.initPublisher(
|
this.publisher = this.OV.initPublisher(
|
||||||
'local-vid-' + this.session.connection.connectionId,
|
undefined,
|
||||||
{
|
{
|
||||||
audioSource: this.sendAudio ? undefined : false,
|
audioSource: this.sendAudio ? undefined : false,
|
||||||
videoSource: this.sendVideo ? (this.optionsVideo === 'screen' ? 'screen' : undefined) : false,
|
videoSource: this.sendVideo ? (this.optionsVideo === 'screen' ? 'screen' : undefined) : false,
|
||||||
publishAudio: this.activeAudio,
|
publishAudio: this.activeAudio,
|
||||||
publishVideo: this.activeVideo,
|
publishVideo: this.activeVideo,
|
||||||
resolution: '640x480',
|
resolution: '640x480',
|
||||||
frameRate: 30,
|
frameRate: 30
|
||||||
insertMode: VideoInsertMode.APPEND
|
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -874,8 +460,6 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.addPublisherEvents(this.publisher);
|
|
||||||
|
|
||||||
if (this.subscribeToRemote) {
|
if (this.subscribeToRemote) {
|
||||||
this.publisher.subscribeToRemote();
|
this.publisher.subscribeToRemote();
|
||||||
}
|
}
|
||||||
|
@ -897,7 +481,6 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
})
|
})
|
||||||
.then(publisher => {
|
.then(publisher => {
|
||||||
this.publisher = publisher;
|
this.publisher = publisher;
|
||||||
this.addPublisherEvents(this.publisher);
|
|
||||||
if (this.subscribeToRemote) {
|
if (this.subscribeToRemote) {
|
||||||
this.publisher.subscribeToRemote();
|
this.publisher.subscribeToRemote();
|
||||||
}
|
}
|
||||||
|
@ -925,75 +508,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
syncSubscribe(session: Session, event) {
|
syncSubscribe(session: Session, event) {
|
||||||
const subscriber: Subscriber = session.subscribe(event.stream, 'remote-vid-' + session.connection.connectionId);
|
this.subscribers.push(session.subscribe(event.stream, undefined));
|
||||||
this.subscribers[subscriber.stream.connection.connectionId] = {
|
|
||||||
'subscriber': subscriber,
|
|
||||||
'subbed': true,
|
|
||||||
'recorder': undefined,
|
|
||||||
'recording': false,
|
|
||||||
'paused': false,
|
|
||||||
'videoElement': undefined
|
|
||||||
};
|
|
||||||
subscriber.on('videoElementCreated', (e: VideoElementEvent) => {
|
|
||||||
if (!event.stream.hasVideo) {
|
|
||||||
$(e.element).css({ 'background-color': '#4d4d4d' });
|
|
||||||
$(e.element).attr('poster', 'assets/images/volume.png');
|
|
||||||
}
|
|
||||||
this.subscribers[subscriber.stream.connection.connectionId].videoElement = e.element;
|
|
||||||
this.updateEventList('videoElementCreated', e.element.id);
|
|
||||||
});
|
|
||||||
subscriber.on('videoPlaying', (e: VideoElementEvent) => {
|
|
||||||
this.appendSubscriberData(e.element, subscriber.stream.connection);
|
|
||||||
this.updateEventList('videoPlaying', e.element.id);
|
|
||||||
});
|
|
||||||
subscriber.on('videoElementDestroyed', (e) => {
|
|
||||||
this.updateEventList('videoElementDestroyed', '(Subscriber)');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
asyncSubscribe(session: Session, event) {
|
|
||||||
session.subscribeAsync(event.stream, 'remote-vid-' + session.connection.connectionId)
|
|
||||||
.then(subscriber => {
|
|
||||||
this.subscribers[subscriber.stream.connection.connectionId] = {
|
|
||||||
'subscriber': subscriber,
|
|
||||||
'subbed': true,
|
|
||||||
'recorder': undefined,
|
|
||||||
'recording': false,
|
|
||||||
'paused': false,
|
|
||||||
'videoElement': undefined
|
|
||||||
};
|
|
||||||
subscriber.on('videoElementCreated', (e: VideoElementEvent) => {
|
|
||||||
if (!event.stream.hasVideo) {
|
|
||||||
$(e.element).css({ 'background-color': '#4d4d4d' });
|
|
||||||
$(e.element).attr('poster', 'assets/images/volume.png');
|
|
||||||
}
|
|
||||||
this.subscribers[subscriber.stream.connection.connectionId].videoElement = e.element;
|
|
||||||
this.updateEventList('videoElementCreated', e.element.id);
|
|
||||||
});
|
|
||||||
subscriber.on('videoPlaying', (e: VideoElementEvent) => {
|
|
||||||
this.appendSubscriberData(e.element, subscriber.stream.connection);
|
|
||||||
this.updateEventList('videoPlaying', e.element.id);
|
|
||||||
});
|
|
||||||
subscriber.on('videoElementDestroyed', (e) => {
|
|
||||||
this.updateEventList('videoElementDestroyed', '(Subscriber)');
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
enableSpeakingEvents() {
|
|
||||||
this.session.on('publisherStartSpeaking', (event) => {
|
|
||||||
});
|
|
||||||
|
|
||||||
this.session.on('publisherStopSpeaking', (event) => {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
disableSpeakingEvents() {
|
|
||||||
this.session.off('publisherStartSpeaking');
|
|
||||||
this.session.off('publisherStopSpeaking');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initGrayVideo(): void {
|
initGrayVideo(): void {
|
||||||
|
@ -1050,7 +565,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
this.sessionName = this.sessionProperties.customSessionId;
|
this.sessionName = this.sessionProperties.customSessionId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
document.getElementById('session-settings-btn').classList.remove('cdk-program-focused');
|
document.getElementById('session-settings-btn-' + this.index).classList.remove('cdk-program-focused');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1064,7 +579,54 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
});
|
});
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe((result: string) => {
|
dialogRef.afterClosed().subscribe((result: string) => {
|
||||||
document.getElementById('session-api-btn').classList.remove('cdk-program-focused');
|
document.getElementById('session-api-btn-' + this.index).classList.remove('cdk-program-focused');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openSessionEventsDialog() {
|
||||||
|
|
||||||
|
const oldValues = {
|
||||||
|
connectionCreated: this.sessionEvents.connectionCreated,
|
||||||
|
connectionDestroyed: this.sessionEvents.connectionDestroyed,
|
||||||
|
sessionDisconnected: this.sessionEvents.sessionDisconnected,
|
||||||
|
streamCreated: this.sessionEvents.streamCreated,
|
||||||
|
streamDestroyed: this.sessionEvents.streamDestroyed,
|
||||||
|
recordingStarted: this.sessionEvents.recordingStarted,
|
||||||
|
recordingStopped: this.sessionEvents.recordingStopped,
|
||||||
|
signal: this.sessionEvents.signal,
|
||||||
|
publisherStartSpeaking: this.sessionEvents.publisherStartSpeaking,
|
||||||
|
publisherStopSpeaking: this.sessionEvents.publisherStopSpeaking
|
||||||
|
};
|
||||||
|
|
||||||
|
const dialogRef = this.dialog.open(EventsDialogComponent, {
|
||||||
|
data: {
|
||||||
|
eventCollection: this.sessionEvents,
|
||||||
|
target: 'Session'
|
||||||
|
},
|
||||||
|
width: '280px',
|
||||||
|
autoFocus: false,
|
||||||
|
disableClose: true
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((result) => {
|
||||||
|
|
||||||
|
if (!!this.session && JSON.stringify(this.sessionEvents) !== JSON.stringify(oldValues)) {
|
||||||
|
this.updateSessionEvents(oldValues, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sessionEvents = {
|
||||||
|
connectionCreated: result.connectionCreated,
|
||||||
|
connectionDestroyed: result.connectionDestroyed,
|
||||||
|
sessionDisconnected: result.sessionDisconnected,
|
||||||
|
streamCreated: result.streamCreated,
|
||||||
|
streamDestroyed: result.streamDestroyed,
|
||||||
|
recordingStarted: result.recordingStarted,
|
||||||
|
recordingStopped: result.recordingStopped,
|
||||||
|
signal: result.signal,
|
||||||
|
publisherStartSpeaking: result.publisherStartSpeaking,
|
||||||
|
publisherStopSpeaking: result.publisherStopSpeaking
|
||||||
|
};
|
||||||
|
document.getElementById('session-events-btn-' + this.index).classList.remove('cdk-program-focused');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1079,4 +641,15 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
udpateEventFromChild(event) {
|
||||||
|
this.updateEventList(event.event, event.content);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSubscriberFromChild(newSubscriber: Subscriber) {
|
||||||
|
const oldSubscriber = this.subscribers.filter(sub => {
|
||||||
|
return sub.stream.streamId === newSubscriber.stream.streamId;
|
||||||
|
})[0];
|
||||||
|
this.subscribers[this.subscribers.indexOf(oldSubscriber)] = newSubscriber;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="instance-div">
|
<div class="instance-div">
|
||||||
<app-openvidu-instance *ngFor="let user of users" [openviduUrl]="openviduUrl" [openviduSecret]="openviduSecret" [sessionConf]="user">
|
<app-openvidu-instance *ngFor="let user of users; let i=index" [openviduUrl]="openviduUrl" [openviduSecret]="openviduSecret" [sessionConf]="user" [index]="i">
|
||||||
</app-openvidu-instance>
|
</app-openvidu-instance>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { Component, Input, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
|
||||||
|
import { StreamManager } from 'openvidu-browser';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-ov-video',
|
||||||
|
template: '<video #videoElement [poster]=""></video>'
|
||||||
|
})
|
||||||
|
export class OpenViduVideoComponent implements AfterViewInit {
|
||||||
|
|
||||||
|
@ViewChild('videoElement') elementRef: ElementRef;
|
||||||
|
|
||||||
|
@Input() poster = '';
|
||||||
|
|
||||||
|
_streamManager: StreamManager;
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
this._streamManager.addVideoElement(this.elementRef.nativeElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
set streamManager(streamManager: StreamManager) {
|
||||||
|
this._streamManager = streamManager;
|
||||||
|
if (!!this.elementRef) {
|
||||||
|
this._streamManager.addVideoElement(this.elementRef.nativeElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
app-ov-video {
|
||||||
|
float: left;
|
||||||
|
height: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-node {
|
||||||
|
width: 120px;
|
||||||
|
height: 90px;
|
||||||
|
float: left;
|
||||||
|
position: relative;
|
||||||
|
margin-left: -120px;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
display: inline-flex;
|
||||||
|
vertical-align: top;
|
||||||
|
margin: 0;
|
||||||
|
background: #ffffff;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
color: #797979;
|
||||||
|
font-weight: 100;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-icons {
|
||||||
|
font-size: 17px;
|
||||||
|
width: 17px;
|
||||||
|
height: 17px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-btn {
|
||||||
|
border: none;
|
||||||
|
background: rgba(255, 255, 255, 0.75);
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0;
|
||||||
|
height: 20px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-btn:hover {
|
||||||
|
color: #4d4d4d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-btn.top-row {
|
||||||
|
margin-top: 0;
|
||||||
|
display: inline-flex;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rec-btn {
|
||||||
|
float: right;
|
||||||
|
color: #ac0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rec-btn:hover {
|
||||||
|
color: #ac000082;
|
||||||
|
}
|
||||||
|
|
||||||
|
.events-btn {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-left-rounded {
|
||||||
|
border-top-left-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-right-rounded {
|
||||||
|
border-top-right-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-left-rounded {
|
||||||
|
border-bottom-left-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-right-rounded {
|
||||||
|
border-bottom-right-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grey-background {
|
||||||
|
background-color: #4d4d4d
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-div {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-div {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
height: 20px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
<div>
|
||||||
|
<app-ov-video [streamManager]="streamManager" [poster]="videoPoster" class="{{videoClasses}}"></app-ov-video>
|
||||||
|
<div *ngIf="!streamManager.remote && showButtons" class="data-node">
|
||||||
|
<div class="top-div">
|
||||||
|
<button class="video-btn events-btn bottom-left-rounded" title="Publisher events" (click)="openPublisherEventsDialog()">
|
||||||
|
<mat-icon aria-label="Publisher events" class="mat-icon material-icons" role="img" aria-hidden="true">notifications</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-div">
|
||||||
|
<button class="video-btn pub-btn" title="Publish/Unpublish" (click)="pubUnpub()">
|
||||||
|
<mat-icon aria-label="Publish or unpublish" class="mat-icon material-icons" role="img" aria-hidden="true">{{pubSubIcon}}</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button class="video-btn pub-video-btn" title="Publish/Unpublish Video" (click)="pubUnpubVideo()">
|
||||||
|
<mat-icon aria-label="Publish or unpublish video" class="mat-icon material-icons" role="img" aria-hidden="true">{{pubSubVideoIcon}}</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button class="video-btn pub-audio-btn" title="Publish/Unpublish Audio" (click)="pubUnpubAudio()">
|
||||||
|
<mat-icon aria-label="Publish or unpublish audio" class="mat-icon material-icons" role="img" aria-hidden="true">{{pubSubAudioIcon}}</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button class="video-btn change-publisher-btn" title="Change publisher" (click)="changePub()">
|
||||||
|
<mat-icon aria-label="Change publisher" class="mat-icon material-icons" role="img" aria-hidden="true">switch_video</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button class="video-btn rec-btn publisher-rec-btn" title="Record" (click)="record()">
|
||||||
|
<mat-icon aria-label="Start/Stop local recording" class="mat-icon material-icons" role="img" aria-hidden="true">
|
||||||
|
{{recordIcon}}</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="!!pauseRecordIcon" class="video-btn rec-btn publisher-rec-btn publisher-rec-pause-btn" title="Pause/Resume"
|
||||||
|
(click)="pauseRecord()">
|
||||||
|
<mat-icon aria-label="Pause/Resume local recording" class="mat-icon material-icons" role="img" aria-hidden="true">
|
||||||
|
{{pauseRecordIcon}}</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="streamManager.remote && showButtons" class="data-node">
|
||||||
|
<div class="top-div">
|
||||||
|
<p class="name bottom-right-rounded">{{streamManager.stream.connection.data}}</p>
|
||||||
|
<button *ngIf="subbed" class="video-btn events-btn bottom-left-rounded" title="Subscriber events" (click)="openSubscriberEventsDialog()">
|
||||||
|
<mat-icon aria-label="Subscriber events" class="mat-icon material-icons" role="img" aria-hidden="true">notifications</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-div">
|
||||||
|
<button class="video-btn sub-btn" title="Subscribe/Unsubscribe" (click)="subUnsub()">
|
||||||
|
<mat-icon aria-label="Subscribe or unsubscribe" class="mat-icon material-icons" role="img" aria-hidden="true">{{pubSubIcon}}</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="!!pubSubVideoIcon" class="video-btn sub-video-btn" title="Subscribe/Unsubscribe Video" (click)="subUnsubVideo()">
|
||||||
|
<mat-icon aria-label="Subscribe or unsubscribe video" class="mat-icon material-icons" role="img" aria-hidden="true">{{pubSubVideoIcon}}</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="!!pubSubAudioIcon" class="video-btn sub-audio-btn" title="Subscribe/Unsubscribe Audio" (click)="subUnsubAudio()">
|
||||||
|
<mat-icon aria-label="Subscribe or unsubscribe audio" class="mat-icon material-icons" role="img" aria-hidden="true">{{pubSubAudioIcon}}</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="!!recordIcon" class="video-btn rec-btn" title="Record" (click)="record()">
|
||||||
|
<mat-icon aria-label="Start/Stop recording" class="mat-icon material-icons" role="img" aria-hidden="true">{{recordIcon}}</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="!!pauseRecordIcon" class="video-btn rec-btn rec-pause-btn" title="Pause/Resume" (click)="pauseRecord()">
|
||||||
|
<mat-icon aria-label="Pause/Resume recording" class="mat-icon material-icons" role="img" aria-hidden="true">{{pauseRecordIcon}}</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,569 @@
|
||||||
|
import { Component, Input, OnInit, ViewChild, ElementRef, Output, EventEmitter, OnDestroy } from '@angular/core';
|
||||||
|
import { MatDialog, MatDialogRef } from '@angular/material';
|
||||||
|
|
||||||
|
import {
|
||||||
|
StreamManager,
|
||||||
|
StreamManagerEvent,
|
||||||
|
VideoElementEvent,
|
||||||
|
Subscriber,
|
||||||
|
Session,
|
||||||
|
LocalRecorder,
|
||||||
|
OpenVidu,
|
||||||
|
Publisher,
|
||||||
|
StreamEvent,
|
||||||
|
VideoInsertMode
|
||||||
|
} from 'openvidu-browser';
|
||||||
|
|
||||||
|
import { EventsDialogComponent } from '../dialogs/events-dialog.component';
|
||||||
|
import { MuteSubscribersService } from '../../services/mute-subscribers.service';
|
||||||
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
|
import { LocalRecordingDialogComponent } from '../dialogs/local-recording-dialog.component';
|
||||||
|
import { ExtensionDialogComponent } from '../dialogs/extension-dialog.component';
|
||||||
|
import { OpenViduVideoComponent } from './ov-video.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-video',
|
||||||
|
templateUrl: './video.component.html',
|
||||||
|
styleUrls: ['./video.component.css']
|
||||||
|
})
|
||||||
|
export class VideoComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
@Input() streamManager: StreamManager;
|
||||||
|
@Input() OV: OpenVidu;
|
||||||
|
@Input() eventCollection: any;
|
||||||
|
|
||||||
|
@Output() updateEventListInParent = new EventEmitter();
|
||||||
|
@Output() reSubbed = new EventEmitter();
|
||||||
|
|
||||||
|
subbed = true;
|
||||||
|
subbedVideo = true;
|
||||||
|
subbedAudio = true;
|
||||||
|
recorder = undefined;
|
||||||
|
recording = false;
|
||||||
|
recordingPaused = false;
|
||||||
|
videoElement = undefined;
|
||||||
|
showButtons = false;
|
||||||
|
videoClasses = '';
|
||||||
|
videoPoster = '';
|
||||||
|
|
||||||
|
unpublished = false;
|
||||||
|
publisherChanged = false;
|
||||||
|
audioMuted = false;
|
||||||
|
videoMuted = false;
|
||||||
|
sendAudio = true;
|
||||||
|
sendVideo = true;
|
||||||
|
sendAudioChange = false;
|
||||||
|
sendVideoChange = false;
|
||||||
|
optionsVideo = '';
|
||||||
|
|
||||||
|
private muteSubscribersSubscription: Subscription;
|
||||||
|
|
||||||
|
// Icons
|
||||||
|
pubSubIcon = 'stop';
|
||||||
|
pubSubVideoIcon = 'videocam';
|
||||||
|
pubSubAudioIcon = 'mic';
|
||||||
|
recordIcon = 'fiber_manual_record';
|
||||||
|
pauseRecordIcon = '';
|
||||||
|
|
||||||
|
constructor(private dialog: MatDialog, private muteSubscribersService: MuteSubscribersService
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
|
||||||
|
if (this.streamManager.remote) {
|
||||||
|
// Init subscriber events
|
||||||
|
this.eventCollection = {
|
||||||
|
videoElementCreated: true,
|
||||||
|
videoElementDestroyed: true,
|
||||||
|
streamPlaying: true
|
||||||
|
};
|
||||||
|
this.updateSubscriberEvents({
|
||||||
|
videoElementCreated: false,
|
||||||
|
videoElementDestroyed: false,
|
||||||
|
streamPlaying: false
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Init publisher events
|
||||||
|
this.eventCollection = {
|
||||||
|
videoElementCreated: true,
|
||||||
|
videoElementDestroyed: true,
|
||||||
|
streamPlaying: true,
|
||||||
|
accessAllowed: true,
|
||||||
|
accessDenied: true,
|
||||||
|
accessDialogOpened: true,
|
||||||
|
accessDialogClosed: true,
|
||||||
|
streamCreated: true,
|
||||||
|
streamDestroyed: true
|
||||||
|
};
|
||||||
|
this.updatePublisherEvents(
|
||||||
|
<Publisher>this.streamManager,
|
||||||
|
{
|
||||||
|
videoElementCreated: false,
|
||||||
|
videoElementDestroyed: false,
|
||||||
|
streamPlaying: false,
|
||||||
|
accessAllowed: false,
|
||||||
|
accessDenied: false,
|
||||||
|
accessDialogOpened: false,
|
||||||
|
accessDialogClosed: false,
|
||||||
|
streamCreated: false,
|
||||||
|
streamDestroyed: false
|
||||||
|
});
|
||||||
|
this.sendAudio = this.streamManager.stream.hasAudio;
|
||||||
|
this.sendVideo = this.streamManager.stream.hasVideo;
|
||||||
|
this.optionsVideo = this.streamManager.stream.typeOfVideo;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.muteSubscribersSubscription = this.muteSubscribersService.mutedEvent$.subscribe(muteOrUnmute => {
|
||||||
|
this.streamManager.videos.forEach(v => {
|
||||||
|
v.video.muted = muteOrUnmute;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (!!this.recorder) {
|
||||||
|
this.recorder.clean();
|
||||||
|
}
|
||||||
|
if (!!this.muteSubscribersSubscription) { this.muteSubscribersSubscription.unsubscribe(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
subUnsub() {
|
||||||
|
const subscriber: Subscriber = <Subscriber>this.streamManager;
|
||||||
|
if (this.subbed) {
|
||||||
|
this.streamManager.stream.session.unsubscribe(subscriber);
|
||||||
|
this.restartRecorder();
|
||||||
|
|
||||||
|
this.pubSubVideoIcon = '';
|
||||||
|
this.pubSubAudioIcon = '';
|
||||||
|
this.recordIcon = '';
|
||||||
|
this.pauseRecordIcon = '';
|
||||||
|
this.pubSubIcon = 'play_arrow';
|
||||||
|
this.subbedVideo = false;
|
||||||
|
this.subbedAudio = false;
|
||||||
|
} else {
|
||||||
|
const oldValues = {
|
||||||
|
videoElementCreated: this.eventCollection.videoElementCreated,
|
||||||
|
videoElementDestroyed: this.eventCollection.videoElementDestroyed,
|
||||||
|
streamPlaying: this.eventCollection.streamPlaying
|
||||||
|
};
|
||||||
|
this.streamManager = this.streamManager.stream.session.subscribe(subscriber.stream, undefined);
|
||||||
|
this.reSubbed.emit(this.streamManager);
|
||||||
|
|
||||||
|
this.pubSubVideoIcon = 'videocam';
|
||||||
|
this.pubSubAudioIcon = 'mic';
|
||||||
|
this.recordIcon = 'fiber_manual_record';
|
||||||
|
this.pauseRecordIcon = '';
|
||||||
|
this.pubSubIcon = 'stop';
|
||||||
|
this.subbedVideo = true;
|
||||||
|
this.subbedAudio = true;
|
||||||
|
|
||||||
|
this.updateSubscriberEvents(oldValues);
|
||||||
|
}
|
||||||
|
this.subbed = !this.subbed;
|
||||||
|
}
|
||||||
|
|
||||||
|
subUnsubVideo(connectionId: string) {
|
||||||
|
const subscriber: Subscriber = <Subscriber>this.streamManager;
|
||||||
|
this.subbedVideo = !this.subbedVideo;
|
||||||
|
subscriber.subscribeToVideo(this.subbedVideo);
|
||||||
|
this.pubSubVideoIcon = this.subbedVideo ? 'videocam' : 'videocam_off';
|
||||||
|
}
|
||||||
|
|
||||||
|
subUnsubAudio(connectionId: string) {
|
||||||
|
const subscriber: Subscriber = <Subscriber>this.streamManager;
|
||||||
|
this.subbedAudio = !this.subbedAudio;
|
||||||
|
subscriber.subscribeToAudio(this.subbedAudio);
|
||||||
|
this.pubSubAudioIcon = this.subbedAudio ? 'mic' : 'mic_off';
|
||||||
|
}
|
||||||
|
|
||||||
|
pubUnpub() {
|
||||||
|
const publisher: Publisher = <Publisher>this.streamManager;
|
||||||
|
if (this.unpublished) {
|
||||||
|
this.streamManager.stream.session.publish(publisher)
|
||||||
|
.then(() => {
|
||||||
|
console.log(publisher);
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.error(e);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.streamManager.stream.session.unpublish(publisher);
|
||||||
|
}
|
||||||
|
this.unpublished = !this.unpublished;
|
||||||
|
this.unpublished ? this.pubSubIcon = 'play_arrow' : this.pubSubIcon = 'stop';
|
||||||
|
}
|
||||||
|
|
||||||
|
pubUnpubVideo() {
|
||||||
|
const publisher: Publisher = <Publisher>this.streamManager;
|
||||||
|
publisher.publishVideo(this.videoMuted);
|
||||||
|
this.videoMuted = !this.videoMuted;
|
||||||
|
this.pubSubVideoIcon = this.videoMuted ? 'videocam_off' : 'videocam';
|
||||||
|
}
|
||||||
|
|
||||||
|
pubUnpubAudio() {
|
||||||
|
const publisher: Publisher = <Publisher>this.streamManager;
|
||||||
|
publisher.publishAudio(this.audioMuted);
|
||||||
|
this.audioMuted = !this.audioMuted;
|
||||||
|
this.pubSubAudioIcon = this.audioMuted ? 'mic_off' : 'mic';
|
||||||
|
}
|
||||||
|
|
||||||
|
changePub() {
|
||||||
|
let screenChange;
|
||||||
|
if (!this.publisherChanged) {
|
||||||
|
if (this.sendAudio && !this.sendVideo) {
|
||||||
|
this.sendAudioChange = false;
|
||||||
|
this.sendVideoChange = true;
|
||||||
|
screenChange = false;
|
||||||
|
} else if (!this.sendAudio && this.sendVideo) {
|
||||||
|
this.sendAudioChange = true;
|
||||||
|
this.sendVideoChange = false;
|
||||||
|
} else if (this.sendAudio && this.sendVideo && this.optionsVideo === 'CAMERA') {
|
||||||
|
this.sendAudioChange = false;
|
||||||
|
this.sendVideoChange = true;
|
||||||
|
screenChange = true;
|
||||||
|
} else if (this.sendAudio && this.sendVideo && this.optionsVideo === 'SCREEN') {
|
||||||
|
this.sendAudioChange = false;
|
||||||
|
this.sendVideoChange = true;
|
||||||
|
screenChange = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.sendAudioChange = this.sendAudio;
|
||||||
|
this.sendVideoChange = this.sendVideo;
|
||||||
|
screenChange = this.optionsVideo === 'SCREEN' ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.audioMuted = false;
|
||||||
|
this.videoMuted = false;
|
||||||
|
this.unpublished = false;
|
||||||
|
|
||||||
|
const otherPublisher = this.OV.initPublisher(
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
audioSource: this.sendAudioChange ? undefined : false,
|
||||||
|
videoSource: this.sendVideoChange ? (screenChange ? 'screen' : undefined) : false,
|
||||||
|
publishAudio: (!this.publisherChanged) ? true : !this.audioMuted,
|
||||||
|
publishVideo: (!this.publisherChanged) ? true : !this.videoMuted,
|
||||||
|
resolution: '640x480',
|
||||||
|
frameRate: 30,
|
||||||
|
insertMode: VideoInsertMode.APPEND
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
if (err) {
|
||||||
|
console.warn(err);
|
||||||
|
if (err.name === 'SCREEN_EXTENSION_NOT_INSTALLED') {
|
||||||
|
this.dialog.open(ExtensionDialogComponent, {
|
||||||
|
data: { url: err.message },
|
||||||
|
disableClose: true,
|
||||||
|
width: '250px'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.updatePublisherEvents(otherPublisher, {
|
||||||
|
videoElementCreated: !this.eventCollection.videoElementCreated,
|
||||||
|
videoElementDestroyed: !this.eventCollection.videoElementDestroyed,
|
||||||
|
streamPlaying: !this.eventCollection.streamPlaying,
|
||||||
|
accessAllowed: !this.eventCollection.accessAllowed,
|
||||||
|
accessDenied: !this.eventCollection.accessDenied,
|
||||||
|
accessDialogOpened: !this.eventCollection.accessDialogOpened,
|
||||||
|
accessDialogClosed: !this.eventCollection.accessDialogClosed,
|
||||||
|
streamCreated: !this.eventCollection.streamCreated,
|
||||||
|
streamDestroyed: !this.eventCollection.streamDestroyed
|
||||||
|
});
|
||||||
|
|
||||||
|
otherPublisher.once('accessAllowed', () => {
|
||||||
|
if (!this.unpublished) {
|
||||||
|
this.streamManager.stream.session.unpublish(<Publisher>this.streamManager);
|
||||||
|
this.streamManager = otherPublisher;
|
||||||
|
}
|
||||||
|
this.streamManager.stream.session.publish(otherPublisher).then(() => {
|
||||||
|
console.log(this.streamManager);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.publisherChanged = !this.publisherChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSubscriberEvents(oldValues) {
|
||||||
|
const sub: Subscriber = <Subscriber>this.streamManager;
|
||||||
|
|
||||||
|
if (this.eventCollection.videoElementCreated) {
|
||||||
|
if (!oldValues.videoElementCreated) {
|
||||||
|
sub.on('videoElementCreated', (event: VideoElementEvent) => {
|
||||||
|
if (!sub.stream.hasVideo) {
|
||||||
|
this.videoClasses = 'grey-background';
|
||||||
|
this.videoPoster = 'assets/images/volume.png';
|
||||||
|
} else {
|
||||||
|
this.videoClasses = '';
|
||||||
|
this.videoPoster = '';
|
||||||
|
}
|
||||||
|
this.updateEventListInParent.emit({
|
||||||
|
event: 'videoElementCreated',
|
||||||
|
content: event.element.id
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sub.off('videoElementCreated');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.eventCollection.videoElementDestroyed) {
|
||||||
|
if (!oldValues.videoElementDestroyed) {
|
||||||
|
sub.on('videoElementDestroyed', (event: VideoElementEvent) => {
|
||||||
|
this.showButtons = false;
|
||||||
|
this.updateEventListInParent.emit({
|
||||||
|
event: 'videoElementDestroyed',
|
||||||
|
content: event.element.id
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sub.off('videoElementDestroyed');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.eventCollection.streamPlaying) {
|
||||||
|
if (!oldValues.streamPlaying) {
|
||||||
|
sub.on('streamPlaying', (event: StreamManagerEvent) => {
|
||||||
|
this.showButtons = true;
|
||||||
|
this.updateEventListInParent.emit({
|
||||||
|
event: 'streamPlaying',
|
||||||
|
content: this.streamManager.stream.streamId
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sub.off('streamPlaying');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePublisherEvents(pub: Publisher, oldValues: any) {
|
||||||
|
if (this.eventCollection.videoElementCreated) {
|
||||||
|
if (!oldValues.videoElementCreated) {
|
||||||
|
pub.on('videoElementCreated', (event: VideoElementEvent) => {
|
||||||
|
if (!pub.stream.hasVideo) {
|
||||||
|
this.videoClasses = 'grey-background';
|
||||||
|
this.videoPoster = 'assets/images/volume.png';
|
||||||
|
} else {
|
||||||
|
this.videoClasses = '';
|
||||||
|
this.videoPoster = '';
|
||||||
|
}
|
||||||
|
this.updateEventListInParent.emit({
|
||||||
|
event: 'videoElementCreated',
|
||||||
|
content: event.element.id
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pub.off('videoElementCreated');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.eventCollection.accessAllowed) {
|
||||||
|
if (!oldValues.accessAllowed) {
|
||||||
|
pub.on('accessAllowed', (e) => {
|
||||||
|
this.updateEventListInParent.emit({
|
||||||
|
event: 'accessAllowed',
|
||||||
|
content: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pub.off('accessAllowed');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.eventCollection.accessDenied) {
|
||||||
|
if (!oldValues.accessDenied) {
|
||||||
|
pub.on('accessDenied', (e) => {
|
||||||
|
this.updateEventListInParent.emit({
|
||||||
|
event: 'accessDenied',
|
||||||
|
content: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pub.off('accessDenied');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.eventCollection.accessDialogOpened) {
|
||||||
|
if (!oldValues.accessDialogOpened) {
|
||||||
|
pub.on('accessDialogOpened', (e) => {
|
||||||
|
this.updateEventListInParent.emit({
|
||||||
|
event: 'accessDialogOpened',
|
||||||
|
content: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pub.off('accessDialogOpened');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.eventCollection.accessDialogClosed) {
|
||||||
|
if (!oldValues.accessDialogClosed) {
|
||||||
|
pub.on('accessDialogClosed', (e) => {
|
||||||
|
this.updateEventListInParent.emit({
|
||||||
|
event: 'accessDialogClosed',
|
||||||
|
content: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pub.off('accessDialogClosed');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.eventCollection.streamCreated) {
|
||||||
|
if (!oldValues.streamCreated) {
|
||||||
|
pub.on('streamCreated', (e: StreamEvent) => {
|
||||||
|
this.updateEventListInParent.emit({
|
||||||
|
event: 'streamCreated',
|
||||||
|
content: e.stream.streamId
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pub.off('streamCreated');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.eventCollection.streamDestroyed) {
|
||||||
|
if (!oldValues.streamDestroyed) {
|
||||||
|
pub.on('streamDestroyed', (e: StreamEvent) => {
|
||||||
|
this.updateEventListInParent.emit({
|
||||||
|
event: 'streamDestroyed',
|
||||||
|
content: e.stream.streamId
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pub.off('streamDestroyed');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.eventCollection.videoElementDestroyed) {
|
||||||
|
if (!oldValues.videoElementDestroyed) {
|
||||||
|
pub.on('videoElementDestroyed', (e: VideoElementEvent) => {
|
||||||
|
this.updateEventListInParent.emit({
|
||||||
|
event: 'videoElementDestroyed',
|
||||||
|
content: '(Publisher)'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pub.off('videoElementDestroyed');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.eventCollection.streamPlaying) {
|
||||||
|
if (!oldValues.streamPlaying) {
|
||||||
|
pub.on('streamPlaying', (event: StreamManagerEvent) => {
|
||||||
|
this.showButtons = true;
|
||||||
|
this.updateEventListInParent.emit({
|
||||||
|
event: 'streamPlaying',
|
||||||
|
content: this.streamManager.stream.streamId
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pub.off('streamPlaying');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openSubscriberEventsDialog() {
|
||||||
|
const oldValues = {
|
||||||
|
videoElementCreated: this.eventCollection.videoElementCreated,
|
||||||
|
videoElementDestroyed: this.eventCollection.videoElementDestroyed,
|
||||||
|
streamPlaying: this.eventCollection.streamPlaying
|
||||||
|
};
|
||||||
|
const dialogRef = this.dialog.open(EventsDialogComponent, {
|
||||||
|
data: {
|
||||||
|
eventCollection: this.eventCollection,
|
||||||
|
target: 'Subscriber'
|
||||||
|
},
|
||||||
|
width: '280px',
|
||||||
|
autoFocus: false,
|
||||||
|
disableClose: true
|
||||||
|
});
|
||||||
|
dialogRef.afterClosed().subscribe((result) => {
|
||||||
|
this.updateSubscriberEvents(oldValues);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
openPublisherEventsDialog() {
|
||||||
|
const oldValues = {
|
||||||
|
videoElementCreated: this.eventCollection.videoElementCreated,
|
||||||
|
videoElementDestroyed: this.eventCollection.videoElementDestroyed,
|
||||||
|
streamPlaying: this.eventCollection.streamPlaying,
|
||||||
|
accessAllowed: this.eventCollection.accessAllowed,
|
||||||
|
accessDenied: this.eventCollection.accessDenied,
|
||||||
|
accessDialogOpened: this.eventCollection.accessDialogOpened,
|
||||||
|
accessDialogClosed: this.eventCollection.accessDialogClosed,
|
||||||
|
streamCreated: this.eventCollection.streamCreated,
|
||||||
|
streamDestroyed: this.eventCollection.streamDestroyed
|
||||||
|
};
|
||||||
|
const dialogRef = this.dialog.open(EventsDialogComponent, {
|
||||||
|
data: {
|
||||||
|
eventCollection: this.eventCollection,
|
||||||
|
target: 'Publisher'
|
||||||
|
},
|
||||||
|
width: '280px',
|
||||||
|
autoFocus: false,
|
||||||
|
disableClose: true
|
||||||
|
});
|
||||||
|
dialogRef.afterClosed().subscribe((result) => {
|
||||||
|
this.updatePublisherEvents(<Publisher>this.streamManager, oldValues);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
record(): void {
|
||||||
|
if (!this.recording) {
|
||||||
|
this.recorder = this.OV.initLocalRecorder(this.streamManager.stream);
|
||||||
|
this.recorder.record();
|
||||||
|
this.recording = true;
|
||||||
|
this.recordIcon = 'stop';
|
||||||
|
this.pauseRecordIcon = 'pause';
|
||||||
|
} else {
|
||||||
|
this.recorder.stop()
|
||||||
|
.then(() => {
|
||||||
|
let dialogRef: MatDialogRef<LocalRecordingDialogComponent>;
|
||||||
|
dialogRef = this.dialog.open(LocalRecordingDialogComponent, {
|
||||||
|
disableClose: true,
|
||||||
|
data: {
|
||||||
|
recorder: this.recorder
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialogRef.componentInstance.myReference = dialogRef;
|
||||||
|
|
||||||
|
dialogRef.afterOpen().subscribe(() => {
|
||||||
|
this.muteSubscribersService.updateMuted(true);
|
||||||
|
this.recorder.preview('recorder-preview').controls = true;
|
||||||
|
});
|
||||||
|
dialogRef.afterClosed().subscribe(() => {
|
||||||
|
this.muteSubscribersService.updateMuted(false);
|
||||||
|
this.restartRecorder();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error stopping LocalRecorder: ' + error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pauseRecord(): void {
|
||||||
|
if (!this.recordingPaused) {
|
||||||
|
this.recorder.pause();
|
||||||
|
this.pauseRecordIcon = 'play_arrow';
|
||||||
|
} else {
|
||||||
|
this.recorder.resume();
|
||||||
|
this.pauseRecordIcon = 'pause';
|
||||||
|
}
|
||||||
|
this.recordingPaused = !this.recordingPaused;
|
||||||
|
}
|
||||||
|
|
||||||
|
private restartRecorder() {
|
||||||
|
this.recording = false;
|
||||||
|
this.recordingPaused = false;
|
||||||
|
this.recordIcon = 'fiber_manual_record';
|
||||||
|
this.pauseRecordIcon = '';
|
||||||
|
if (!!this.recorder) {
|
||||||
|
this.recorder.clean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Binary file not shown.
|
@ -9,11 +9,6 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
|
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g="
|
|
||||||
crossorigin="anonymous"></script>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.myEvents = '';
|
window.myEvents = '';
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* fallback */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Material Icons';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url(/assets/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-icons {
|
||||||
|
font-family: 'Material Icons';
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 1;
|
||||||
|
letter-spacing: normal;
|
||||||
|
text-transform: none;
|
||||||
|
display: inline-block;
|
||||||
|
white-space: nowrap;
|
||||||
|
word-wrap: normal;
|
||||||
|
direction: ltr;
|
||||||
|
-webkit-font-feature-settings: 'liga';
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
|
@ -38,67 +38,6 @@ button {
|
||||||
line-height: 15px !important;
|
line-height: 15px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-container video {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-container div.data-node {
|
|
||||||
width: 120px;
|
|
||||||
height: 90px;
|
|
||||||
float: left;
|
|
||||||
position: relative;
|
|
||||||
margin-left: -120px;
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-container p {
|
|
||||||
margin-top: 0;
|
|
||||||
width: fit-content;
|
|
||||||
background: #ffffff;
|
|
||||||
padding-left: 5px;
|
|
||||||
padding-right: 5px;
|
|
||||||
color: #797979;
|
|
||||||
font-weight: 100;
|
|
||||||
font-size: 14px;
|
|
||||||
border-bottom-right-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-container div.data-node .sub-btn {
|
|
||||||
outline: 0;
|
|
||||||
border: none;
|
|
||||||
background: rgba(255, 255, 255, 0.75);
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0;
|
|
||||||
margin-top: 40px;
|
|
||||||
border-top-right-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-container div.data-node .sub-btn:hover {
|
|
||||||
color: #4d4d4d;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-container div.data-node .rec-btn {
|
|
||||||
float: right;
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
border-top-left-radius: 2px;
|
|
||||||
color: #ac0000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-container div.data-node .rec-btn:hover {
|
|
||||||
color: #ac000082;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-container div.data-node .rec-btn.publisher-rec-btn {
|
|
||||||
margin-top: 70px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-container div.data-node .material-icons {
|
|
||||||
font-size: 17px;
|
|
||||||
width: 17px;
|
|
||||||
height: 17px;
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-expansion-panel-body {
|
.mat-expansion-panel-body {
|
||||||
font-size: 9.5px !important;
|
font-size: 9.5px !important;
|
||||||
padding: 0 9px 0px !important;
|
padding: 0 9px 0px !important;
|
||||||
|
|
Loading…
Reference in New Issue