openvidu-browser fix: streamDestroyed only triggered by Publisher after streamCreated

pull/73/head
pabloFuente 2018-05-31 13:08:34 +02:00
parent 37cdb9ccf0
commit 2f2a42c439
11 changed files with 325 additions and 186 deletions

View File

@ -795,9 +795,12 @@ export class Session implements EventDispatcher {
}
if (!!this.connection.stream) {
// Make Publisher object dispatch 'streamDestroyed' event (if there's a local stream)
// Dispose Publisher's local stream
this.connection.stream.disposeWebRtcPeer();
this.connection.stream.ee.emitEvent('local-stream-destroyed-by-disconnect', [reason]);
if (this.connection.stream.isLocalStreamPublished) {
// Make Publisher object dispatch 'streamDestroyed' event if the Stream was published
this.connection.stream.ee.emitEvent('local-stream-destroyed-by-disconnect', [reason]);
}
}
if (!this.connection.disposed) {

View File

@ -14,14 +14,15 @@ import { VideoComponent } from './components/video/video.component';
import { OpenViduVideoComponent } from './components/video/ov-video.component';
import { ExtensionDialogComponent } from './components/dialogs/extension-dialog.component';
import { LocalRecordingDialogComponent } from './components/dialogs/local-recording-dialog.component';
import { SessionPropertiesDialogComponent } from './components/dialogs/session-properties-dialog.component';
import { SessionApiDialogComponent } from './components/dialogs/session-api-dialog.component';
import { EventsDialogComponent } from './components/dialogs/events-dialog.component';
import { PublisherPropertiesDialogComponent } from './components/dialogs/publisher-properties-dialog.component';
import { OpenviduRestService } from './services/openvidu-rest.service';
import { OpenviduParamsService } from './services/openvidu-params.service';
import { TestFeedService } from './services/test-feed.service';
import { MuteSubscribersService } from './services/mute-subscribers.service';
import { SessionPropertiesDialogComponent } from './components/dialogs/session-properties-dialog.component';
import { SessionApiDialogComponent } from './components/dialogs/session-api-dialog.component';
import { EventsDialogComponent } from './components/dialogs/events-dialog.component';
@NgModule({
declarations: [
@ -35,7 +36,8 @@ import { EventsDialogComponent } from './components/dialogs/events-dialog.compon
SessionPropertiesDialogComponent,
SessionApiDialogComponent,
EventsDialogComponent,
LocalRecordingDialogComponent
LocalRecordingDialogComponent,
PublisherPropertiesDialogComponent
],
imports: [
BrowserModule,
@ -56,7 +58,8 @@ import { EventsDialogComponent } from './components/dialogs/events-dialog.compon
SessionPropertiesDialogComponent,
SessionApiDialogComponent,
EventsDialogComponent,
LocalRecordingDialogComponent
LocalRecordingDialogComponent,
PublisherPropertiesDialogComponent
],
bootstrap: [AppComponent]
})

View File

@ -0,0 +1,31 @@
mat-chip {
margin: 0 0 5px 0 !important;
height: 12px;
max-width: 180px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
cursor: pointer !important;
}
mat-divider {
margin-top: 10px !important;
margin-bottom: 5px !important;
}
button.device-btn {
height: 30px;
width: 30px;
line-height: 30px;
}
button.device-btn mat-icon {
width: 20px;
height: 20px;
font-size: 20px;
line-height: 20px;
}
div.mat-form-field-subscript-wrapper {
margin-top: 0 !important;
}

View File

@ -0,0 +1,48 @@
<div>
<h2 mat-dialog-title>Publisher properties</h2>
<mat-dialog-content>
<mat-checkbox (click)="toggleAudio()" [checked]="publisherProperties.audioSource !== false">Audio
</mat-checkbox>
<mat-checkbox (click)="toggleVideo()" [checked]="publisherProperties.videoSource !== false">Video
</mat-checkbox>
<mat-checkbox [(ngModel)]="publisherProperties.publishAudio" (click)="publisherProperties.publishAudio = !publisherProperties.publishAudio">Publish audio</mat-checkbox>
<mat-checkbox [(ngModel)]="publisherProperties.publishVideo" (click)="publisherProperties.publishVideo = !publisherProperties.publishVideo">Publish video</mat-checkbox>
<mat-checkbox [(ngModel)]="publisherProperties.mirror" (click)="publisherProperties.mirror = !publisherProperties.mirror">Mirror</mat-checkbox>
<mat-divider></mat-divider>
<mat-form-field>
<input matInput placeholder="Audio source" [(ngModel)]="audioSource" [disabled]="(publisherProperties.audioSource === false)">
</mat-form-field>
<button mat-icon-button class="device-btn" title="List audio devices" (click)="listAudioDevices()">
<mat-icon aria-label="List audio devices">add_circle</mat-icon>
</button>
<button *ngIf="audioDevices.length > 0" mat-icon-button class="device-btn" title="Clear audio devices" (click)="audioDevices = []">
<mat-icon aria-label="Clear audio devices">clear</mat-icon>
</button>
<mat-chip-list *ngIf="audioDevices.length > 0">
<mat-chip *ngFor="let audioDevice of audioDevices" (click)="audioSource=audioDevice.deviceId">{{audioDevice.label}}</mat-chip>
</mat-chip-list>
<mat-form-field>
<input matInput placeholder="Video source" [(ngModel)]="videoSource" [disabled]="(publisherProperties.videoSource === false)">
</mat-form-field>
<button mat-icon-button class="device-btn" title="List video devices" (click)="listVideoDevices()">
<mat-icon aria-label="List video devices">add_circle</mat-icon>
</button>
<button *ngIf="videoDevices.length > 0" mat-icon-button class="device-btn" title="Clear video devices" (click)="videoDevices = []">
<mat-icon aria-label="Clear video devices">clear</mat-icon>
</button>
<mat-chip-list *ngIf="videoDevices.length > 0">
<mat-chip *ngFor="let videoDevice of videoDevices" (click)="videoSource=videoDevice.deviceId">{{videoDevice.label}}</mat-chip>
</mat-chip-list>
<mat-divider></mat-divider>
<mat-form-field>
<input matInput placeholder="Resolution" [(ngModel)]="publisherProperties.resolution">
</mat-form-field>
<mat-form-field>
<input matInput placeholder="Framerate" [(ngModel)]="publisherProperties.frameRate" type="number">
</mat-form-field>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button [mat-dialog-close]="initValue">CANCEL</button>
<button mat-button [mat-dialog-close]="setCloseValue()">SAVE</button>
</mat-dialog-actions>
</div>

View File

@ -0,0 +1,105 @@
import { Component, Inject } from '@angular/core';
import { MatDialog, MAT_DIALOG_DATA, MatDialogConfig, MatDialogRef, MAT_CHECKBOX_CLICK_ACTION } from '@angular/material';
import { SessionProperties, MediaMode, RecordingMode, RecordingLayout } from 'openvidu-node-client';
import { PublisherProperties, OpenVidu } from 'openvidu-browser';
@Component({
selector: 'app-publisher-properties-dialog',
templateUrl: './publisher-properties-dialog.component.html',
styleUrls: ['./publisher-properties-dialog.component.css'],
providers: [
{ provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'noop' }
]
})
export class PublisherPropertiesDialogComponent {
OV: OpenVidu;
publisherProperties: PublisherProperties;
initValue: PublisherProperties;
audioSource;
videoSource;
audioSourceAux;
videoSourceAux;
audioDevices = [];
videoDevices = [];
private mediaMode = MediaMode;
private recordingMode = RecordingMode;
private defaultRecordingLayout = RecordingLayout;
constructor(public dialogRef: MatDialogRef<PublisherPropertiesDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: PublisherProperties) {
this.publisherProperties = data;
this.OV = new OpenVidu();
this.initValue = Object.assign({}, this.publisherProperties);
this.audioSource = typeof this.publisherProperties.audioSource === 'string' ? this.publisherProperties.audioSource : undefined;
this.videoSource = typeof this.publisherProperties.videoSource === 'string' ? this.publisherProperties.videoSource : undefined;
}
toggleAudio(): void {
if (this.publisherProperties.audioSource === false) {
this.publisherProperties.audioSource = this.audioSource;
this.audioSource = this.audioSourceAux;
} else {
this.audioSourceAux = this.audioSource;
this.audioSource = undefined;
this.publisherProperties.audioSource = false;
}
}
toggleVideo(): void {
if (this.publisherProperties.videoSource === false) {
this.publisherProperties.videoSource = this.videoSource;
this.videoSource = this.videoSourceAux;
} else {
this.videoSourceAux = this.videoSource;
this.videoSource = undefined;
this.publisherProperties.videoSource = false;
}
}
setCloseValue(): PublisherProperties {
if (typeof this.audioSource === 'string') {
if (!!this.audioSource) {
this.publisherProperties.audioSource = this.audioSource;
} else {
this.publisherProperties.audioSource = undefined;
}
}
if (typeof this.videoSource === 'string') {
if (!!this.videoSource) {
this.publisherProperties.videoSource = this.videoSource;
} else {
this.publisherProperties.videoSource = undefined;
}
}
return this.publisherProperties;
}
listAudioDevices() {
this.audioDevices = [];
this.OV.getDevices().then(devices => {
devices.forEach(device => {
if (device.kind === 'audioinput') {
this.audioDevices.push(device);
}
});
});
}
listVideoDevices() {
this.videoDevices = [];
this.OV.getDevices().then(devices => {
devices.forEach(device => {
if (device.kind === 'videoinput') {
this.videoDevices.push(device);
}
});
});
}
}

View File

@ -48,9 +48,9 @@ export class SessionPropertiesDialogComponent {
sessionProperties: SessionProperties;
private mediaMode = MediaMode;
private recordingMode = RecordingMode;
private defaultRecordingLayout = RecordingLayout;
mediaMode = MediaMode;
recordingMode = RecordingMode;
defaultRecordingLayout = RecordingLayout;
constructor(public dialogRef: MatDialogRef<SessionPropertiesDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: SessionProperties) {

View File

@ -33,10 +33,8 @@
<div>
<button class="join-btn" mat-button (click)="joinSession()" [disabled]="session">JOIN</button>
<mat-checkbox class="subscribe-checkbox" name="subscribeTo" (change)="toggleSubscribeTo()" [checked]="subscribeTo && checkSubscribeTo"
[disabled]="session">Subscribe</mat-checkbox>
<mat-checkbox class="publish-checkbox" name="publishTo" (change)="togglePublishTo()" [checked]="publishTo && checkPublishTo"
[disabled]="session || disablePublishTo">Publish</mat-checkbox>
<mat-checkbox class="subscribe-checkbox" name="subscribeTo" (click)="toggleSubscribeTo()" [checked]="subscribeTo" [disabled]="session">Subscribe</mat-checkbox>
<mat-checkbox class="publish-checkbox" name="publishTo" (click)="togglePublishTo()" [checked]="publishTo" [disabled]="session">Publish</mat-checkbox>
</div>
<div class="inner-card" fxLayout="row" fxLayoutAlign="start start">
@ -45,45 +43,45 @@
<div>
<h4>Send</h4>
<div>
<mat-checkbox class="send-audio-checkbox" name="sendAudio" (change)="toggleSendAudio()" [checked]="sendAudio && checkSendAudio"
[disabled]="session || disableSendAudio">Audio</mat-checkbox>
<mat-checkbox class="send-video-checkbox" name="sendVideo" (change)="toggleSendVideo()" [checked]="sendVideo && checkSendVideo"
[disabled]="session || disableSendVideo">Video</mat-checkbox>
<mat-checkbox class="send-audio-checkbox" name="sendAudio" (click)="toggleSendAudio()" [checked]="publisherProperties.audioSource !== false"
[disabled]="session || !publishTo">Audio</mat-checkbox>
<mat-checkbox class="send-video-checkbox" name="sendVideo" (click)="toggleSendVideo()" [checked]="publisherProperties.videoSource !== false"
[disabled]="session || !publishTo">Video</mat-checkbox>
</div>
</div>
<div style="padding-top: 5px;">
<h4>Enter active</h4>
<div>
<mat-checkbox class="active-audio-checkbox" name="activeAudio" (change)="toggleActiveAudio()" [checked]="activeAudio && checkActiveAudio"
[disabled]="session || disableActiveAudio">Audio</mat-checkbox>
<mat-checkbox class="active-video-checkbox" name="activeVideo" (change)="toggleActiveVideo()" [checked]="activeVideo && checkActiveVideo"
[disabled]="session || disableActiveVideo">Video</mat-checkbox>
<mat-checkbox class="active-audio-checkbox" name="activeAudio" [(ngModel)]="publisherProperties.publishAudio" (click)="publisherProperties.publishAudio = !publisherProperties.publishAudio"
[disabled]="session || !publishTo">Audio</mat-checkbox>
<mat-checkbox class="active-video-checkbox" name="activeVideo" [(ngModel)]="publisherProperties.publishVideo" (click)="publisherProperties.publishVideo = !publisherProperties.publishVideo"
[disabled]="session || !publishTo">Video</mat-checkbox>
</div>
</div>
</div>
<div fxFlex="35">
<mat-radio-group [(ngModel)]="optionsVideo" [disabled]="session || disableRadioButtons" [ngModelOptions]="{standalone: true}">
<mat-radio-group [(ngModel)]="optionsVideo" (change)="updateOptionsVideo($event)" [disabled]="session || !publishTo" [ngModelOptions]="{standalone: true}">
<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">Video</mat-radio-button>
</div>
<div>
<mat-radio-button class="screen-radio" value="screen" [checked]="checkRadioScreen && optionsVideo==='screen'">Screen</mat-radio-button>
<mat-radio-button class="screen-radio" value="screen">Screen</mat-radio-button>
</div>
</mat-radio-group>
<mat-checkbox class="subscribe-remote-check" name="subscribeToRemote" (change)="subscribeToRemote = !subscribeToRemote" [disabled]="(!sendAudio && !sendVideo) || !publishTo || session"
[checked]="(sendAudio || sendVideo) && publishTo && subscribeToRemote">Subscribe
<mat-checkbox class="subscribe-remote-check" name="subscribeToRemote" (click)="subscribeToRemote = !subscribeToRemote" [disabled]="!publishTo || session"
[checked]="publishTo && subscribeToRemote">Subscribe
<br>to remote</mat-checkbox>
</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">
<button mat-icon-button title="Publisher properties" [id]="'publisher-settings-btn-' + index" class="mat-icon-custom" (click)="openPublisherPropertiesDialog()"
[disabled]="!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)">
<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>
@ -129,9 +127,10 @@
</div>
<div [attr.id]="'remote-vid-' + session.connection.connectionId" fxFlex="240px" class="video-container">
<div [attr.id]="'local-vid-' + session.connection.connectionId"></div>
<app-video *ngIf="this.publisher" [streamManager]="this.publisher" [OV]="OV" (updateEventListInParent)="udpateEventFromChild($event)">
<app-video *ngIf="this.publisher" [streamManager]="this.publisher" [OV]="OV" [properties]="publisherProperties" (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 *ngFor="let subscriber of this.subscribers" [streamManager]="subscriber" [OV]="OV" (updateEventListInParent)="udpateEventFromChild($event)"
(reSubbed)="updateSubscriberFromChild($event)">
</app-video>
</div>
</div>

View File

@ -7,7 +7,8 @@ import { Subscription } from 'rxjs/Subscription';
import {
OpenVidu, Session, Subscriber, Publisher, Stream, Connection,
LocalRecorder, VideoInsertMode, StreamEvent, ConnectionEvent,
SessionDisconnectedEvent, SignalEvent, RecordingEvent, VideoElementEvent, PublisherSpeakingEvent, StreamManagerEvent, StreamManager
SessionDisconnectedEvent, SignalEvent, RecordingEvent, VideoElementEvent,
PublisherSpeakingEvent, StreamManagerEvent, StreamManager, PublisherProperties
} from 'openvidu-browser';
import {
OpenVidu as OpenViduAPI,
@ -17,21 +18,19 @@ import {
RecordingMode,
RecordingLayout
} from 'openvidu-node-client';
import { MatDialog, MatDialogRef } from '@angular/material';
import { MatDialog, MatDialogRef, MAT_CHECKBOX_CLICK_ACTION } from '@angular/material';
import { ExtensionDialogComponent } from '../dialogs/extension-dialog.component';
import { LocalRecordingDialogComponent } from '../dialogs/local-recording-dialog.component';
import { TestFeedService } from '../../services/test-feed.service';
import { MuteSubscribersService } from '../../services/mute-subscribers.service';
import { EventsDialogComponent } from '../dialogs/events-dialog.component';
import { SessionPropertiesDialogComponent } from '../dialogs/session-properties-dialog.component';
import { SessionApiDialogComponent } from '../dialogs/session-api-dialog.component';
import { PublisherPropertiesDialogComponent } from '../dialogs/publisher-properties-dialog.component';
export interface SessionConf {
subscribeTo: boolean;
publishTo: boolean;
sendAudio: boolean;
sendVideo: boolean;
startSession: boolean;
}
@ -43,7 +42,10 @@ export interface OpenViduEvent {
@Component({
selector: 'app-openvidu-instance',
templateUrl: './openvidu-instance.component.html',
styleUrls: ['./openvidu-instance.component.css']
styleUrls: ['./openvidu-instance.component.css'],
providers: [
{ provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'noop' }
]
})
export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
@ -66,30 +68,10 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
// Session options
subscribeTo;
publishTo;
sendAudio;
sendVideo;
activeAudio = true;
activeVideo = true;
sendVideoRadio = true;
subscribeToRemote = false;
optionsVideo = 'video';
// Form 'check' and 'disable' attributes
checkSubscribeTo = true;
checkPublishTo = true;
checkSendAudio = true;
checkSendVideo = true;
checkActiveAudio = true;
checkActiveVideo = true;
checkRadioVideo = true;
checkRadioScreen = false;
disablePublishTo = false;
disableSendAudio = false;
disableSendVideo = false;
disableActiveAudio = false;
disableActiveVideo = false;
disableRadioButtons = false;
// OpenVidu Browser objects
OV: OpenVidu;
session: Session;
@ -105,6 +87,18 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
customSessionId: ''
};
publisherProperties: PublisherProperties = {
audioSource: undefined,
videoSource: undefined,
frameRate: 30,
resolution: '640x480',
mirror: true,
publishAudio: true,
publishVideo: true
};
publisherPropertiesAux: PublisherProperties;
sessionEvents = {
connectionCreated: true,
connectionDestroyed: true,
@ -139,14 +133,11 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
ngOnInit() {
this.subscribeTo = this.sessionConf.subscribeTo;
this.publishTo = this.sessionConf.publishTo;
this.sendAudio = this.sessionConf.sendAudio;
this.sendVideo = this.sessionConf.sendVideo;
this.publisherPropertiesAux = Object.assign({}, this.publisherProperties);
if (!this.publishTo) {
this.publishTo = !this.publishTo;
this.togglePublishTo();
}
if (this.sessionConf.startSession) {
this.joinSession();
}
@ -242,76 +233,49 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
togglePublishTo(): void {
this.publishTo = !this.publishTo;
this.sendAudio = this.publishTo;
this.sendVideo = this.publishTo;
this.activeAudio = this.publishTo;
this.activeVideo = this.publishTo;
this.checkPublishTo = this.publishTo;
this.checkSendAudio = this.publishTo;
this.checkSendVideo = this.publishTo;
this.checkActiveAudio = this.publishTo;
this.checkActiveVideo = this.publishTo;
if (this.publishTo) {
this.checkRadioVideo = true;
this.optionsVideo = 'video';
this.publisherProperties = this.publisherPropertiesAux;
} else {
this.checkRadioVideo = false;
this.optionsVideo = '';
this.publisherPropertiesAux = Object.assign({}, this.publisherProperties);
this.publisherProperties.publishAudio = false;
this.publisherProperties.publishVideo = false;
this.publisherProperties.audioSource = false;
this.publisherProperties.videoSource = false;
}
this.disableSendAudio = !this.publishTo;
this.disableSendVideo = !this.publishTo;
this.disableActiveAudio = !this.publishTo;
this.disableActiveVideo = !this.publishTo;
this.disableRadioButtons = !this.publishTo;
if (this.publishTo) {
this.optionsVideo = 'video';
} else {
this.optionsVideo = '';
}
this.subscribeToRemote = false;
}
toggleSendAudio(): void {
this.sendAudio = !this.sendAudio;
this.activeAudio = this.sendAudio;
this.checkActiveAudio = this.sendAudio;
this.disableActiveAudio = !this.sendAudio;
if (!this.sendAudio && !this.sendVideo && this.publishTo) {
this.togglePublishTo();
if (this.publisherProperties.audioSource === false) {
this.publisherProperties.audioSource = this.publisherPropertiesAux.audioSource;
} else {
this.publisherPropertiesAux.audioSource = this.publisherProperties.audioSource;
this.publisherProperties.audioSource = false;
}
}
toggleSendVideo(): void {
this.sendVideo = !this.sendVideo;
this.activeVideo = this.sendVideo;
this.checkActiveVideo = this.sendVideo;
this.checkRadioScreen = false;
if (this.sendVideo) {
this.checkRadioVideo = true;
this.optionsVideo = 'video';
if (this.publisherProperties.videoSource === false) {
this.publisherProperties.videoSource = this.publisherPropertiesAux.videoSource;
} else {
this.checkRadioVideo = false;
this.optionsVideo = '';
}
this.disableActiveVideo = !this.sendVideo;
this.disableRadioButtons = !this.sendVideo;
if (!this.sendAudio && !this.sendVideo && this.publishTo) {
this.togglePublishTo();
this.publisherPropertiesAux.videoSource = this.publisherProperties.videoSource;
this.publisherProperties.videoSource = false;
}
}
toggleActiveAudio(): void {
this.activeAudio = !this.activeAudio;
this.publisherProperties.publishAudio = !this.publisherProperties.publishAudio;
}
toggleActiveVideo(): void {
this.activeVideo = !this.activeVideo;
this.publisherProperties.publishVideo = !this.publisherProperties.publishVideo;
}
sendMessage(): void {
@ -438,14 +402,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
syncInitPublisher() {
this.publisher = this.OV.initPublisher(
undefined,
{
audioSource: this.sendAudio ? undefined : false,
videoSource: this.sendVideo ? (this.optionsVideo === 'screen' ? 'screen' : undefined) : false,
publishAudio: this.activeAudio,
publishVideo: this.activeVideo,
resolution: '640x480',
frameRate: 30
},
this.publisherProperties,
(err) => {
if (err) {
console.warn(err);
@ -467,46 +424,6 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
this.session.publish(this.publisher);
}
asyncInitPublisher() {
this.OV.initPublisherAsync(
'local-vid-' + this.session.connection.connectionId,
{
audioSource: this.sendAudio ? undefined : false,
videoSource: this.sendVideo ? (this.optionsVideo === 'screen' ? 'screen' : undefined) : false,
publishAudio: this.activeAudio,
publishVideo: this.activeVideo,
resolution: '640x480',
frameRate: 30,
insertMode: VideoInsertMode.APPEND
})
.then(publisher => {
this.publisher = publisher;
if (this.subscribeToRemote) {
this.publisher.subscribeToRemote();
}
this.session.publish(this.publisher)
.then(() => {
console.log(this.publisher);
})
.catch(e => {
console.error(e);
});
})
.catch(err => {
if (err) {
console.error(err);
this.openviduError = err;
if (err.name === 'SCREEN_EXTENSION_NOT_INSTALLED') {
this.dialog.open(ExtensionDialogComponent, {
data: { url: err.message },
disableClose: true,
width: '250px'
});
}
}
});
}
syncSubscribe(session: Session, event) {
this.subscribers.push(session.subscribe(event.stream, undefined));
}
@ -575,7 +492,8 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
openVidu: new OpenViduAPI(this.openviduUrl, this.openviduSecret),
sessionId: !!this.session ? this.session.sessionId : this.sessionName
},
width: '280px'
width: '280px',
disableClose: true
});
dialogRef.afterClosed().subscribe((result: string) => {
@ -630,6 +548,22 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
});
}
openPublisherPropertiesDialog() {
const dialogRef = this.dialog.open(PublisherPropertiesDialogComponent, {
data: this.publisherProperties,
width: '300px',
disableClose: true
});
dialogRef.afterClosed().subscribe((result: PublisherProperties) => {
if (!!result) {
this.publisherProperties = result;
this.optionsVideo = this.publisherProperties.videoSource === 'screen' ? 'screen' : 'video';
}
document.getElementById('publisher-settings-btn-' + this.index).classList.remove('cdk-program-focused');
});
}
getToken(): Promise<string> {
const OV_NodeClient = new OpenViduAPI(this.openviduUrl, this.openviduSecret);
if (!this.sessionProperties.customSessionId) {
@ -652,4 +586,19 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
this.subscribers[this.subscribers.indexOf(oldSubscriber)] = newSubscriber;
}
updateOptionsVideo(change) {
if (change.value === 'screen') {
this.publisherPropertiesAux.videoSource = this.publisherProperties.videoSource;
this.publisherProperties.videoSource = 'screen';
} else {
this.publisherProperties.videoSource = this.publisherPropertiesAux.videoSource;
}
}
isVideo(): boolean {
return (this.publisherProperties.videoSource === undefined ||
typeof this.publisherProperties.videoSource === 'string' &&
this.publisherProperties.videoSource !== 'screen');
}
}

View File

@ -50,8 +50,6 @@ export class TestSessionsComponent implements OnInit, OnDestroy {
this.users.push({
subscribeTo: true,
publishTo: true,
sendAudio: true,
sendVideo: true,
startSession: false
});
}
@ -69,8 +67,6 @@ export class TestSessionsComponent implements OnInit, OnDestroy {
this.users.push({
subscribeTo: true,
publishTo: true,
sendAudio: true,
sendVideo: true,
startSession: this.autoJoin
});
}
@ -81,8 +77,6 @@ export class TestSessionsComponent implements OnInit, OnDestroy {
this.users.push({
subscribeTo: true,
publishTo: false,
sendAudio: false,
sendVideo: false,
startSession: this.autoJoin
});
}
@ -93,8 +87,6 @@ export class TestSessionsComponent implements OnInit, OnDestroy {
this.users.push({
subscribeTo: false,
publishTo: true,
sendAudio: true,
sendVideo: true,
startSession: this.autoJoin
});
}

View File

@ -10,10 +10,10 @@
<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()">
<button *ngIf="streamManager.stream.hasVideo" 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()">
<button *ngIf="streamManager.stream.hasAudio" 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()">
@ -41,10 +41,10 @@
<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()">
<button *ngIf="streamManager.stream.hasVideo && !!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()">
<button *ngIf="streamManager.stream.hasAudio && !!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()">

View File

@ -29,6 +29,7 @@ import { OpenViduVideoComponent } from './ov-video.component';
export class VideoComponent implements OnInit, OnDestroy {
@Input() streamManager: StreamManager;
@Input() properties: any;
@Input() OV: OpenVidu;
@Input() eventCollection: any;
@ -111,13 +112,19 @@ export class VideoComponent implements OnInit, OnDestroy {
});
this.sendAudio = this.streamManager.stream.hasAudio;
this.sendVideo = this.streamManager.stream.hasVideo;
this.audioMuted = !this.properties.publishAudio;
this.videoMuted = !this.properties.publishVideo;
this.pubSubAudioIcon = this.audioMuted ? 'mic_off' : 'mic';
this.pubSubVideoIcon = this.videoMuted ? 'videocam_off' : 'videocam';
this.optionsVideo = this.streamManager.stream.typeOfVideo;
}
this.muteSubscribersSubscription = this.muteSubscribersService.mutedEvent$.subscribe(muteOrUnmute => {
this.streamManager.videos.forEach(v => {
v.video.muted = muteOrUnmute;
});
if (this.streamManager.remote) {
this.streamManager.videos.forEach(v => {
v.video.muted = muteOrUnmute;
});
}
});
}
@ -196,15 +203,15 @@ export class VideoComponent implements OnInit, OnDestroy {
pubUnpubVideo() {
const publisher: Publisher = <Publisher>this.streamManager;
publisher.publishVideo(this.videoMuted);
this.videoMuted = !this.videoMuted;
publisher.publishVideo(!this.videoMuted);
this.pubSubVideoIcon = this.videoMuted ? 'videocam_off' : 'videocam';
}
pubUnpubAudio() {
const publisher: Publisher = <Publisher>this.streamManager;
publisher.publishAudio(this.audioMuted);
this.audioMuted = !this.audioMuted;
publisher.publishAudio(!this.audioMuted);
this.pubSubAudioIcon = this.audioMuted ? 'mic_off' : 'mic';
}
@ -233,8 +240,6 @@ export class VideoComponent implements OnInit, OnDestroy {
screenChange = this.optionsVideo === 'SCREEN' ? true : false;
}
this.audioMuted = false;
this.videoMuted = false;
this.unpublished = false;
const otherPublisher = this.OV.initPublisher(
@ -242,8 +247,8 @@ export class VideoComponent implements OnInit, OnDestroy {
{
audioSource: this.sendAudioChange ? undefined : false,
videoSource: this.sendVideoChange ? (screenChange ? 'screen' : undefined) : false,
publishAudio: (!this.publisherChanged) ? true : !this.audioMuted,
publishVideo: (!this.publisherChanged) ? true : !this.videoMuted,
publishAudio: !this.audioMuted,
publishVideo: !this.videoMuted,
resolution: '640x480',
frameRate: 30,
insertMode: VideoInsertMode.APPEND
@ -272,13 +277,17 @@ export class VideoComponent implements OnInit, OnDestroy {
streamDestroyed: !this.eventCollection.streamDestroyed
});
const oldPublisher = <Publisher>this.streamManager;
if (oldPublisher.isSubscribedToRemote) {
otherPublisher.subscribeToRemote(true);
}
otherPublisher.once('accessAllowed', () => {
if (!this.unpublished) {
this.streamManager.stream.session.unpublish(<Publisher>this.streamManager);
this.streamManager = otherPublisher;
this.streamManager.stream.session.unpublish(oldPublisher);
}
this.streamManager.stream.session.publish(otherPublisher).then(() => {
console.log(this.streamManager);
this.streamManager = otherPublisher;
});
});
@ -455,7 +464,7 @@ export class VideoComponent implements OnInit, OnDestroy {
this.showButtons = true;
this.updateEventListInParent.emit({
event: 'streamPlaying',
content: this.streamManager.stream.streamId
content: pub.stream.streamId
});
});
}