import { Injectable } from '@angular/core' ; import { IOpenViduWebRTC } from './openvidu-webrtc.interface' ; import { PublisherProperties , Publisher , Connection , OpenVidu , Session , SignalOptions } from 'openvidu-browser' ; import { Signal } from '../../types/singal-type' ; import { LoggerService } from '../logger/logger.service' ; import { ILogger } from '../../types/logger-type' ; import { LocalUsersService } from '../local-users/local-users.service' ; import { ScreenType } from '../../types/video-type' ; import { environment } from '../../../../environments/environment' ; @ Injectable ( { providedIn : 'root' } ) export class OpenViduWebrtcService implements IOpenViduWebRTC { private OV : OpenVidu = null ; private OVScreen : OpenVidu = null ; private webcamSession : Session = null ; private screenSession : Session = null ; private videoSource = undefined ; private audioSource = undefined ; private screenMediaStream : MediaStream = null ; private webcamMediaStream : MediaStream = null ; private log : ILogger ; constructor ( private loggerSrv , private localUsersSrv ) { this . log = this . loggerSrv . get ( 'OpenViduWebRTCService' ) ; } initialize ( ) { this . OV = new OpenVidu ( ) ; this . OVScreen = new OpenVidu ( ) ; if ( environment . production ) { this . OV . enableProdMode ( ) ; this . OVScreen . enableProdMode ( ) ; } } initSessions ( ) { this . initializeWebcamSession ( ) ; this . initializeScreenSession ( ) ; } getWebcamSession ( ) { return this . webcamSession ; } isWebcamSessionConnected ( ) { return ! ! this . webcamSession . capabilities ; } initializeWebcamSession ( ) { this . webcamSession = this . OV . initSession ( ) ; } initializeScreenSession ( ) { this . screenSession = this . OVScreen . initSession ( ) ; } getScreenSession ( ) { return this . screenSession ; } isScreenSessionConnected ( ) { return ! ! this . screenSession . capabilities ; } async connectWebcamSession ( token ) { if ( ! ! token ) { this . log . d ( 'Connecting webcam session' ) ; const webcamUsername = this . localUsersSrv . getWebcamUserName ( ) ; const webcamAvatar = this . localUsersSrv . getAvatar ( ) ; await this . webcamSession . connect ( token , { clientData : webcamUsername , avatar : webcamAvatar } ) ; } } disconnectWebcamSession ( ) { if ( this . webcamSession ) { this . log . d ( 'Disconnecting webcam session' ) ; this . webcamSession . disconnect ( ) ; this . webcamSession = null ; } } async connectScreenSession ( token ) { if ( ! ! token ) { this . log . d ( 'Connecting screen session' ) ; const screenUsername = this . localUsersSrv . getScreenUserName ( ) ; const webcamAvatar = this . localUsersSrv . getAvatar ( ) ; await this . screenSession . connect ( token , { clientData : screenUsername , avatar : webcamAvatar } ) ; } } disconnectScreenSession ( ) { if ( this . screenSession ) { this . log . d ( 'Disconnecting screen session' ) ; this . screenSession . disconnect ( ) ; this . screenSession = null ; } } disconnect ( ) { this . disconnectWebcamSession ( ) ; this . disconnectScreenSession ( ) ; this . videoSource = undefined ; this . audioSource = undefined ; this . stopVideoTracks ( this . localUsersSrv . getWebcamPublisher ( ) ?. stream ?. getMediaStream ( ) ) ; this . stopVideoTracks ( this . localUsersSrv . getScreenPublisher ( ) ?. stream ?. getMediaStream ( ) ) ; this . stopAudioTracks ( this . localUsersSrv . getWebcamPublisher ( ) ?. stream ?. getMediaStream ( ) ) ; this . stopAudioTracks ( this . localUsersSrv . getScreenPublisher ( ) ?. stream ?. getMediaStream ( ) ) ; } initPublisher ( targetElement , properties ) { this . log . d ( 'Initializing publisher with properties: ' , properties ) ; const publisher = this . OV . initPublisher ( targetElement , properties ) ; publisher . once ( 'streamPlaying' , ( ) => { ( < HTMLElement > publisher . videos [ 0 ] . video ) . parentElement . classList . remove ( 'custom-class' ) ; } ) ; return publisher ; } async initPublisherAsync ( targetElement , properties ) { this . log . d ( 'Initializing publisher with properties: ' , properties ) ; const publisher = await this . OV . initPublisherAsync ( targetElement , properties ) ; publisher . once ( 'streamPlaying' , ( ) => { ( < HTMLElement > publisher . videos [ 0 ] . video ) . parentElement . classList . remove ( 'custom-class' ) ; } ) ; return publisher ; } destroyWebcamPublisher ( ) { const publisher = this . localUsersSrv . getWebcamPublisher ( ) ; if ( ! ! publisher ) { if ( publisher . stream . getWebRtcPeer ( ) ) { publisher . stream . disposeWebRtcPeer ( ) ; } publisher . stream . disposeMediaStream ( ) ; this . localUsersSrv . setWebcamPublisher ( publisher ) ; } } destroyScreenPublisher ( ) { const publisher = this . localUsersSrv . getScreenPublisher ( ) ; if ( ! ! publisher ) { if ( publisher . stream . getWebRtcPeer ( ) ) { publisher . stream . disposeWebRtcPeer ( ) ; } publisher . stream . disposeMediaStream ( ) ; this . localUsersSrv . setScreenPublisher ( publisher ) ; } } async publishWebcamPublisher ( ) { if ( this . webcamSession ?. capabilities ?. publish ) { const publisher = this . localUsersSrv . getWebcamPublisher ( ) ; if ( ! ! publisher ) { return await this . webcamSession . publish ( publisher ) ; } } this . log . e ( 'Webcam publisher cannot be published' ) ; } unpublishWebcamPublisher ( ) { const publisher = this . localUsersSrv . getWebcamPublisher ( ) ; if ( ! ! publisher ) { this . publishScreenAudio ( this . localUsersSrv . hasWebcamAudioActive ( ) ) ; this . webcamSession . unpublish ( publisher ) ; } } async publishScreenPublisher ( ) { if ( this . screenSession ?. capabilities ?. publish ) { const publisher = this . localUsersSrv . getScreenPublisher ( ) ; if ( ! ! publisher ) { return await this . screenSession . publish ( publisher ) ; } } this . log . e ( 'Screen publisher cannot be published' ) ; } unpublishScreenPublisher ( ) { const publisher = this . localUsersSrv . getScreenPublisher ( ) ; if ( ! ! publisher ) { this . screenSession . unpublish ( publisher ) ; } } publishWebcamVideo ( active ) { this . localUsersSrv . getWebcamPublisher ( ) . publishVideo ( active ) ; this . localUsersSrv . updateUsersStatus ( ) ; } publishWebcamAudio ( active ) { const publisher = this . localUsersSrv . getWebcamPublisher ( ) ; if ( ! ! publisher ) { publisher . publishAudio ( active ) ; } } publishScreenAudio ( active ) { const publisher = this . localUsersSrv . getScreenPublisher ( ) ; if ( ! ! publisher ) { publisher . publishAudio ( active ) ; } } replaceTrack ( videoSource , audioSource , mirror = true ) { return new Promise ( ( resolve , reject ) => { if ( ! ! videoSource ) { this . log . d ( 'Replacing video track ' + videoSource ) ; this . videoSource = videoSource ; } if ( ! ! audioSource ) { this . log . d ( 'Replacing audio track ' + audioSource ) ; this . audioSource = audioSource ; } this . destroyWebcamPublisher ( ) ; const properties = this . createPublisherProperties ( this . videoSource , this . audioSource , this . localUsersSrv . hasWebcamVideoActive ( ) , this . localUsersSrv . hasWebcamAudioActive ( ) , mirror ) ; const publisher = this . initPublisher ( undefined , properties ) ; this . localUsersSrv . setWebcamPublisher ( publisher ) ; publisher . once ( 'streamPlaying' , ( ) => { this . localUsersSrv . setWebcamPublisher ( publisher ) ; resolve ( ) ; } ) ; publisher . once ( 'accessDenied' , ( ) => { reject ( ) ; } ) ; } ) ; } sendSignal ( type , connection ? , data ? ) { const signalOptions = { data : JSON . stringify ( data ) , type : type , to : connection ? [ connection ] : undefined } ; this . webcamSession . signal ( signalOptions ) ; } sendNicknameSignal ( connection ? ) { if ( this . needSendNicknameSignal ( ) ) { const signalOptions = { data : JSON . stringify ( { clientData : this . localUsersSrv . getWebcamUserName ( ) } ) , type : 'nicknameChanged' , to : connection ? [ connection ] : undefined } ; this . getWebcamSession ( ) ?. signal ( signalOptions ) ; signalOptions . data = JSON . stringify ( { clientData : this . localUsersSrv . getScreenUserName ( ) } ) ; this . getScreenSession ( ) ?. signal ( signalOptions ) ; } } createPublisherProperties ( videoSource , audioSource , publishVideo , publishAudio , mirror ) { return { videoSource , audioSource , publishVideo , publishAudio , mirror } ; } async replaceScreenTrack ( ) { const videoSource = ScreenType . SCREEN ; const hasAudio = ! this . localUsersSrv . isWebCamEnabled ( ) ; const properties = this . createPublisherProperties ( videoSource , undefined , true , hasAudio , false ) ; this . stopScreenTracks ( ) ; this . screenMediaStream = await this . OVScreen . getUserMedia ( properties ) ; await this . localUsersSrv . getScreenPublisher ( ) . replaceTrack ( this . screenMediaStream . getVideoTracks ( ) [ 0 ] ) ; } stopAudioTracks ( mediaStream ) { mediaStream ?. getAudioTracks ( ) . forEach ( ( track ) => { track . stop ( ) ; track . enabled = false ; } ) ; this . webcamMediaStream ?. getAudioTracks ( ) . forEach ( ( track ) => { track . stop ( ) ; } ) ; } stopVideoTracks ( mediaStream ) { mediaStream ?. getVideoTracks ( ) . forEach ( ( track ) => { track . stop ( ) ; } ) ; } needSendNicknameSignal ( ) { const oldNickname = JSON . parse ( this . webcamSession . connection . data ) . clientData ; return oldNickname !== this . localUsersSrv . getWebcamUserName ( ) ; } isMyOwnConnection ( connectionId ) { return ( this . webcamSession ?. connection ?. connectionId === connectionId || this . screenSession ?. connection ?. connectionId === connectionId ) ; } getSessionOfUserConnected ( ) { return this . localUsersSrv . isWebCamEnabled ( ) ? this . webcamSession : this . screenSession ; } private stopScreenTracks ( ) { if ( this . screenMediaStream ) { this . stopAudioTracks ( this . screenMediaStream ) ; this . stopVideoTracks ( this . screenMediaStream ) ; } } }