openvidu-components: Moved component logic to openvidu service

Moved toggle screen, toggle video and toggle audio logic from toolbar and prejoin component to openvidu service with the aim of avoiding code duplications and being able to provide a powerful method to the components user
pull/713/head
csantosm 2022-03-31 12:25:02 +02:00
parent fccde40641
commit 98fbe060a3
5 changed files with 177 additions and 234 deletions

View File

@ -1,11 +1,9 @@
import { Component, HostListener, OnDestroy, OnInit, Output, EventEmitter } from '@angular/core';
import { Publisher, PublisherProperties } from 'openvidu-browser';
import { OpenViduErrorName } from 'openvidu-browser/lib/OpenViduInternal/Enums/OpenViduError';
import { PublisherProperties } from 'openvidu-browser';
import { Subscription } from 'rxjs';
import { CustomDevice } from '../../models/device.model';
import { ILogger } from '../../models/logger.model';
import { ParticipantAbstractModel, ParticipantProperties } from '../../models/participant.model';
import { ActionService } from '../../services/action/action.service';
import { ParticipantAbstractModel } from '../../models/participant.model';
import { DeviceService } from '../../services/device/device.service';
import { LayoutService } from '../../services/layout/layout.service';
import { LoggerService } from '../../services/logger/logger.service';
@ -96,19 +94,13 @@ export class PreJoinComponent implements OnInit, OnDestroy {
const pp: PublisherProperties = { videoSource, audioSource: this.microphoneSelected.device, mirror };
await this.openviduService.republishTrack(pp);
this.cameraSelected = videoSource;
this.deviceSrv.setCameraSelected(this.cameraSelected);
}
if (this.isVideoMuted) {
// Publish Webcam video
this.openviduService.publishVideo(this.participantService.getMyCameraPublisher(), true);
this.isVideoMuted = false;
this.deviceSrv.setCameraSelected(videoSource);
this.cameraSelected = this.deviceSrv.getCameraSelected();
}
}
async onMicrophoneSelected(event: any) {
const audioSource = event?.value;
// Is New deviceId different than older?
if (this.deviceSrv.needUpdateAudioTrack(audioSource)) {
//TODO: Uncomment this when replaceTrack issue is fixed
// const pp: PublisherProperties = { audioSource, videoSource: false };
@ -118,83 +110,21 @@ export class PreJoinComponent implements OnInit, OnDestroy {
const pp: PublisherProperties = { videoSource: this.cameraSelected.device, audioSource, mirror };
await this.openviduService.republishTrack(pp);
this.microphoneSelected = audioSource;
this.deviceSrv.setMicSelected(this.microphoneSelected);
}
if (this.isAudioMuted) {
// Enable microphone
this.openviduService.publishAudio(this.participantService.getMyCameraPublisher(), true);
this.isAudioMuted = true;
this.deviceSrv.setMicSelected(audioSource);
this.microphoneSelected = this.deviceSrv.getMicrophoneSelected();
}
}
toggleCam() {
async toggleCam() {
const publish = this.isVideoMuted;
this.openviduService.publishVideo(this.participantService.getMyCameraPublisher(), publish);
if (this.participantService.haveICameraAndScreenActive()) {
// Cam will not published, disable webcam with screensharing active
this.participantService.disableWebcamStream();
this.openviduService.publishAudio(this.participantService.getMyScreenPublisher(), publish);
} else if (this.participantService.isOnlyMyScreenActive()) {
// Cam will be published, enable webcam
this.participantService.enableWebcamStream();
}
await this.openviduService.muteVideo(publish);
this.isVideoMuted = !this.isVideoMuted;
this.storageSrv.setVideoMuted(this.isVideoMuted);
}
// async toggleScreenShare() {
// // Disabling screenShare
// if (this.participantService.haveICameraAndScreenActive()) {
// this.participantService.disableScreenUser();
// return;
// }
// // Enabling screenShare
// if (this.participantService.isOnlyMyCameraActive()) {
// const willThereBeWebcam = this.participantService.isMyCameraActive() && this.participantService.hasCameraVideoActive();
// const hasAudio = willThereBeWebcam ? false : this.hasAudioDevices && this.isAudioMuted;
// const properties: PublisherProperties = {
// videoSource: ScreenType.SCREEN,
// audioSource: this.hasAudioDevices ? undefined : null,
// publishVideo: true,
// publishAudio: hasAudio,
// mirror: false
// };
// const screenPublisher = await this.openviduService.initPublisher(undefined, properties);
// screenPublisher.on('accessAllowed', (event) => {
// screenPublisher.stream
// .getMediaStream()
// .getVideoTracks()[0]
// .addEventListener('ended', () => {
// this.log.d('Clicked native stop button. Stopping screen sharing');
// this.toggleScreenShare();
// });
// this.participantService.activeMyScreenShare(screenPublisher);
// if (!this.participantService.hasCameraVideoActive()) {
// this.participantService.disableWebcamUser();
// }
// });
// screenPublisher.on('accessDenied', (error: any) => {
// if (error && error.name === 'SCREEN_SHARING_NOT_SUPPORTED') {
// this.actionService.openDialog('Error sharing screen', 'Your browser does not support screen sharing');
// }
// });
// return;
// }
// // Disabling screnShare and enabling webcam
// this.participantService.enableWebcamUser();
// this.participantService.disableScreenUser();
// }
toggleMic() {
const publish = this.isAudioMuted;
this.openviduService.publishAudio(this.participantService.getMyCameraPublisher(), publish);
this.openviduService.muteAudio(publish);
this.isAudioMuted = !this.isAudioMuted;
this.storageSrv.setAudioMuted(this.isAudioMuted);
}

View File

@ -19,8 +19,7 @@ import { DocumentService } from '../../services/document/document.service';
import { OpenViduService } from '../../services/openvidu/openvidu.service';
import { LoggerService } from '../../services/logger/logger.service';
import { ILogger } from '../../models/logger.model';
import { ScreenType } from '../../models/video-type.model';
import { PublisherProperties, Session } from 'openvidu-browser';
import { Session } from 'openvidu-browser';
import { ActionService } from '../../services/action/action.service';
import { DeviceService } from '../../services/device/device.service';
import { ChatMessage } from '../../models/chat.model';
@ -286,16 +285,13 @@ export class ToolbarComponent implements OnInit, OnDestroy {
/**
* @ignore
*/
toggleMicrophone() {
async toggleMicrophone() {
this.onMicrophoneButtonClicked.emit();
if (this.participantService.isMyCameraActive()) {
this.openviduService.publishAudio(
this.participantService.getMyCameraPublisher(),
!this.participantService.hasCameraAudioActive()
);
} else {
this.openviduService.publishAudio(this.participantService.getMyScreenPublisher(), !this.participantService.hasScreenAudioActive());
try {
await this.openviduService.muteAudio(!this.isAudioActive);
} catch (error) {
this.log.e('There was an error toggling microphone:', error.code, error.message);
this.actionService.openDialog('There was an error toggling camera', error?.error || error?.message);
}
}
@ -307,32 +303,10 @@ export class ToolbarComponent implements OnInit, OnDestroy {
try {
const publishVideo = !this.participantService.hasCameraVideoActive();
const publishAudio = this.participantService.hasCameraAudioActive();
// Disabling webcam
if (this.participantService.haveICameraAndScreenActive()) {
this.openviduService.publishVideo(this.participantService.getMyCameraPublisher(), publishVideo);
this.participantService.disableWebcamStream();
this.openviduService.unpublish(this.participantService.getMyCameraPublisher());
this.openviduService.publishAudio(this.participantService.getMyScreenPublisher(), publishAudio);
return;
}
// Enabling webcam
if (this.participantService.isOnlyMyScreenActive()) {
const hasAudio = this.participantService.hasScreenAudioActive();
if (!this.openviduService.isWebcamSessionConnected()) {
await this.openviduService.connectSession(this.openviduService.getWebcamSession(), this.tokenService.getWebcamToken());
}
await this.openviduService.publish(this.participantService.getMyCameraPublisher());
this.openviduService.publishAudio(this.participantService.getMyScreenPublisher(), false);
this.openviduService.publishAudio(this.participantService.getMyCameraPublisher(), hasAudio);
this.participantService.enableWebcamStream();
}
// Muting/unmuting webcam
this.openviduService.publishVideo(this.participantService.getMyCameraPublisher(), publishVideo);
await this.openviduService.muteVideo(publishVideo);
} catch (error) {
this.log.e('There was an error toggling camera:', error.code, error.message);
this.actionService.openDialog('There was an error toggling camera:', error?.error || error?.message);
this.actionService.openDialog('There was an error toggling camera', error?.error || error?.message);
}
}
@ -343,76 +317,12 @@ export class ToolbarComponent implements OnInit, OnDestroy {
this.onScreenshareButtonClicked.emit();
try {
// Disabling screenShare
if (this.participantService.haveICameraAndScreenActive()) {
this.participantService.disableScreenStream();
this.openviduService.unpublish(this.participantService.getMyScreenPublisher());
return;
}
// Enabling screenShare
if (this.participantService.isOnlyMyCameraActive()) {
const willThereBeWebcam = this.participantService.isMyCameraActive() && this.participantService.hasCameraVideoActive();
const hasAudio = willThereBeWebcam ? false : this.hasAudioDevices && this.participantService.hasCameraAudioActive();
const properties: PublisherProperties = {
videoSource: ScreenType.SCREEN,
audioSource: this.hasAudioDevices ? undefined : null,
publishVideo: true,
publishAudio: hasAudio,
mirror: false
};
const screenPublisher = await this.openviduService.initPublisher(undefined, properties);
screenPublisher.once('accessAllowed', async (event) => {
// Listen to event fired when native stop button is clicked
screenPublisher.stream
.getMediaStream()
.getVideoTracks()[0]
.addEventListener('ended', () => {
this.log.d('Clicked native stop button. Stopping screen sharing');
this.toggleScreenShare();
});
this.log.d('ACCESS ALOWED screenPublisher');
this.participantService.activeMyScreenShare(screenPublisher);
if (!this.openviduService.isScreenSessionConnected()) {
await this.openviduService.connectSession(
this.openviduService.getScreenSession(),
this.tokenService.getScreenToken()
);
}
await this.openviduService.publish(this.participantService.getMyScreenPublisher());
// this.openviduService.sendNicknameSignal();
if (!this.participantService.hasCameraVideoActive()) {
// Disabling webcam
this.participantService.disableWebcamStream();
this.openviduService.unpublish(this.participantService.getMyCameraPublisher());
}
});
screenPublisher.once('accessDenied', (error: any) => {
this.log.e(error);
await this.openviduService.toggleScreenshare();
} catch (error) {
this.log.e('There was an error toggling screen share', error.code, error.message);
if (error && error.name === 'SCREEN_SHARING_NOT_SUPPORTED') {
this.actionService.openDialog('Error sharing screen', 'Your browser does not support screen sharing');
}
});
return;
}
// Disabling screnShare and enabling webcam
const hasAudio = this.participantService.hasScreenAudioActive();
if (!this.openviduService.isWebcamSessionConnected()) {
await this.openviduService.connectSession(this.openviduService.getWebcamSession(), this.tokenService.getWebcamToken());
}
await this.openviduService.publish(this.participantService.getMyCameraPublisher());
this.openviduService.publishAudio(this.participantService.getMyScreenPublisher(), false);
this.openviduService.publishAudio(this.participantService.getMyCameraPublisher(), hasAudio);
this.participantService.enableWebcamStream();
this.participantService.disableScreenStream();
this.openviduService.unpublish(this.participantService.getMyScreenPublisher());
} catch (error) {
this.log.e('There was an error toggling screen share:', error.code, error.message);
this.actionService.openDialog('There was an error toggling screen share:', error?.error || error?.message);
}
}

View File

@ -3,8 +3,6 @@ import { ParticipantProperties, StreamModel } from '../models/participant.model'
export interface OpenViduAngularConfig {
production?: boolean,
participantFactory?: ParticipantFactoryFunction,
webcomponent?: boolean
}
export type ParticipantFactoryFunction = (props: ParticipantProperties, streamModel: StreamModel) => any;

View File

@ -1,14 +1,5 @@
import { Injectable } from '@angular/core';
import {
Connection,
OpenVidu,
OpenViduError,
OpenViduErrorName,
Publisher,
PublisherProperties,
Session,
SignalOptions
} from 'openvidu-browser';
import { Connection, OpenVidu, Publisher, PublisherProperties, Session, SignalOptions } from 'openvidu-browser';
import { LoggerService } from '../logger/logger.service';
@ -18,8 +9,9 @@ import { OpenViduAngularConfigService } from '../config/openvidu-angular.config.
import { PlatformService } from '../platform/platform.service';
import { DeviceService } from '../device/device.service';
import { CameraType } from '../../models/device.model';
import { VideoType } from '../../models/video-type.model';
import { ScreenType, VideoType } from '../../models/video-type.model';
import { ParticipantService } from '../participant/participant.service';
import { TokenService } from '../token/token.service';
@Injectable({
providedIn: 'root'
@ -41,7 +33,8 @@ export class OpenViduService {
protected platformService: PlatformService,
protected loggerSrv: LoggerService,
private participantService: ParticipantService,
protected deviceService: DeviceService
protected deviceService: DeviceService,
protected tokenService: TokenService
) {
this.log = this.loggerSrv.get('OpenViduService');
}
@ -51,6 +44,11 @@ export class OpenViduService {
*/
initialize() {
this.OV = new OpenVidu();
this.OV.setAdvancedConfiguration({
publisherSpeakingEventsOptions: {
interval: 50
}
});
if (this.openviduAngularConfigSrv.isProduction()) this.OV.enableProdMode();
this.webcamSession = this.OV.initSession();
@ -163,8 +161,6 @@ export class OpenViduService {
// audioSource = undefined;
}
// const videoSource = publishVideo ? this.deviceService.getCameraSelected().device : false;
// const audioSource = publishAudio ? this.deviceService.getMicrophoneSelected().device : false;
const mirror = this.deviceService.getCameraSelected() && this.deviceService.getCameraSelected().type === CameraType.FRONT;
const properties: PublisherProperties = {
videoSource,
@ -213,10 +209,10 @@ export class OpenViduService {
/**
* @internal
*/
unpublish(publisher: Publisher): void {
private unpublish(publisher: Publisher): void {
if (!!publisher) {
if (publisher === this.participantService.getMyCameraPublisher()) {
this.publishAudio(this.participantService.getMyScreenPublisher(), this.participantService.hasCameraAudioActive());
this.publishAudioAux(this.participantService.getMyScreenPublisher(), this.participantService.hasCameraAudioActive());
this.webcamSession.unpublish(publisher);
} else if (publisher === this.participantService.getMyScreenPublisher()) {
this.screenSession.unpublish(publisher);
@ -224,20 +220,127 @@ export class OpenViduService {
}
}
/**
* @internal
*/
publishVideo(publisher: Publisher, value: boolean): void {
if (!!publisher) {
publisher.publishVideo(value);
this.participantService.updateLocalParticipant();
async muteVideo(mute: boolean): Promise<void> {
const publishAudio = this.participantService.hasCameraAudioActive();
// const publishVideo = !this.participantService.hasCameraVideoActive();
// Disabling webcam
if (this.participantService.haveICameraAndScreenActive()) {
this.publishVideoAux(this.participantService.getMyCameraPublisher(), mute);
this.participantService.disableWebcamStream();
this.unpublish(this.participantService.getMyCameraPublisher());
this.publishAudioAux(this.participantService.getMyScreenPublisher(), publishAudio);
} else if (this.participantService.isOnlyMyScreenActive()) {
// Enabling webcam
const hasAudio = this.participantService.hasScreenAudioActive();
console.warn('Es audio activo?', hasAudio);
if (!this.isWebcamSessionConnected()) {
//TODO: should be the token in th participant?
await this.connectSession(this.getWebcamSession(), this.tokenService.getWebcamToken());
}
await this.publish(this.participantService.getMyCameraPublisher());
this.publishVideoAux(this.participantService.getMyCameraPublisher(), true);
this.publishAudioAux(this.participantService.getMyScreenPublisher(), false);
this.publishAudioAux(this.participantService.getMyCameraPublisher(), hasAudio);
this.participantService.enableWebcamStream();
} else {
// Muting/unmuting webcam
this.publishVideoAux(this.participantService.getMyCameraPublisher(), mute);
}
}
/**
* @internal
*/
publishAudio(publisher: Publisher, value: boolean): void {
private publishVideoAux(publisher: Publisher, value: boolean): void {
if (!!publisher) {
publisher.publishVideo(value);
this.participantService.updateLocalParticipant();
}
}
async muteAudio(value: boolean): Promise<void> {
if (this.participantService.isMyCameraActive()) {
if (this.participantService.isMyScreenActive() && this.participantService.hasScreenAudioActive()) {
this.publishAudioAux(this.participantService.getMyScreenPublisher(), false);
}
this.publishAudioAux(this.participantService.getMyCameraPublisher(), value);
} else {
this.publishAudioAux(this.participantService.getMyScreenPublisher(), value);
}
}
async toggleScreenshare() {
if (this.participantService.haveICameraAndScreenActive()) {
// Disabling screenShare
this.participantService.disableScreenStream();
this.unpublish(this.participantService.getMyScreenPublisher());
} else if (this.participantService.isOnlyMyCameraActive()) {
// I only have the camera published
const hasAudioDevicesAvailable = this.deviceService.hasAudioDeviceAvailable();
const willWebcamBePresent = this.participantService.isMyCameraActive() && this.participantService.hasCameraVideoActive();
const hasAudio = willWebcamBePresent ? false : hasAudioDevicesAvailable && this.participantService.hasCameraAudioActive();
console.warn('will be audio active', hasAudio);
const properties: PublisherProperties = {
videoSource: ScreenType.SCREEN,
audioSource: hasAudioDevicesAvailable ? this.deviceService.getMicrophoneSelected().device : null,
publishVideo: true,
publishAudio: hasAudio,
mirror: false
};
const screenPublisher = await this.initPublisher(undefined, properties);
screenPublisher.once('accessAllowed', async () => {
// Listen to event fired when native stop button is clicked
screenPublisher.stream
.getMediaStream()
.getVideoTracks()[0]
.addEventListener('ended', async () => {
this.log.d('Clicked native stop button. Stopping screen sharing');
await this.toggleScreenshare();
});
// Enabling screenShare
this.participantService.activeMyScreenShare(screenPublisher);
if (!this.isScreenSessionConnected()) {
await this.connectSession(this.getScreenSession(), this.tokenService.getScreenToken());
}
await this.publish(this.participantService.getMyScreenPublisher());
if (!this.participantService.hasCameraVideoActive()) {
// Disabling webcam
this.participantService.disableWebcamStream();
this.unpublish(this.participantService.getMyCameraPublisher());
}
});
screenPublisher.once('accessDenied', (error: any) => {
return Promise.reject(error);
});
} else {
// I only have my screenshare active and I have no camera or it is muted
const hasAudio = this.participantService.hasScreenAudioActive();
// Enable webcam
if (!this.isWebcamSessionConnected()) {
await this.connectSession(this.getWebcamSession(), this.tokenService.getWebcamToken());
}
await this.publish(this.participantService.getMyCameraPublisher());
this.publishAudioAux(this.participantService.getMyCameraPublisher(), hasAudio);
this.participantService.enableWebcamStream();
// Disabling screenshare
this.participantService.disableScreenStream();
this.unpublish(this.participantService.getMyScreenPublisher());
}
}
/**
* @internal
*/
private publishAudioAux(publisher: Publisher, value: boolean): void {
if (!!publisher) {
publisher.publishAudio(value);
this.participantService.updateLocalParticipant();
@ -368,32 +471,33 @@ export class OpenViduService {
}
}
private async createMediaStream(pp: PublisherProperties): Promise<MediaStream> {
let mediaStream: MediaStream;
const isFirefoxPlatform = this.platformService.isFirefox();
const isReplacingAudio = !!pp.audioSource;
const isReplacingVideo = !!pp.videoSource;
//TODO: Uncomment this section when replaceTrack issue is fixed
// private async createMediaStream(pp: PublisherProperties): Promise<MediaStream> {
// let mediaStream: MediaStream;
// const isFirefoxPlatform = this.platformService.isFirefox();
// const isReplacingAudio = !!pp.audioSource;
// const isReplacingVideo = !!pp.videoSource;
try {
mediaStream = await this.OV.getUserMedia(pp);
} catch (error) {
if ((<OpenViduError>error).name === OpenViduErrorName.DEVICE_ACCESS_DENIED) {
if (isFirefoxPlatform) {
this.log.w('The device requested is not available. Restoring the older one');
// The track requested is not available so we are getting the old tracks ids for recovering the track
if (isReplacingVideo) {
pp.videoSource = this.deviceService.getCameraSelected().device;
} else if (isReplacingAudio) {
pp.audioSource = this.deviceService.getMicrophoneSelected().device;
}
mediaStream = await this.OV.getUserMedia(pp);
// TODO show error alert informing that the new device is not available
}
}
} finally {
return mediaStream;
}
}
// try {
// mediaStream = await this.OV.getUserMedia(pp);
// } catch (error) {
// if ((<OpenViduError>error).name === OpenViduErrorName.DEVICE_ACCESS_DENIED) {
// if (isFirefoxPlatform) {
// this.log.w('The device requested is not available. Restoring the older one');
// // The track requested is not available so we are getting the old tracks ids for recovering the track
// if (isReplacingVideo) {
// pp.videoSource = this.deviceService.getCameraSelected().device;
// } else if (isReplacingAudio) {
// pp.audioSource = this.deviceService.getMicrophoneSelected().device;
// }
// mediaStream = await this.OV.getUserMedia(pp);
// // TODO show error alert informing that the new device is not available
// }
// }
// } finally {
// return mediaStream;
// }
// }
/**
* @internal

View File

@ -41,6 +41,7 @@ export * from './lib/config/openvidu-angular.config';
export * from './lib/models/logger.model';
export * from './lib/models/video-type.model';
export * from './lib/models/notification-options.model';
export * from './lib/models/token.model';
// Pipes
export * from './lib/pipes/participant.pipe';