import AudioProfile from '../audioprofile/AudioProfile' ; import AudioVideoController from '../audiovideocontroller/AudioVideoController' ; import AudioVideoObserver from '../audiovideoobserver/AudioVideoObserver' ; import ContentShareObserver from '../contentshareobserver/ContentShareObserver' ; import Destroyable from '../destroyable/Destroyable' ; import MeetingSessionConfiguration from '../meetingsession/MeetingSessionConfiguration' ; import MeetingSessionCredentials from '../meetingsession/MeetingSessionCredentials' ; import MeetingSessionStatus from '../meetingsession/MeetingSessionStatus' ; import DefaultModality from '../modality/DefaultModality' ; import AsyncScheduler from '../scheduler/AsyncScheduler' ; import { Maybe } from '../utils/Types' ; import VideoTile from '../videotile/VideoTile' ; import ContentShareConstants from './ContentShareConstants' ; import ContentShareController from './ContentShareController' ; import ContentShareMediaStreamBroker from './ContentShareMediaStreamBroker' ; export default class DefaultContentShareController implements ContentShareController , AudioVideoObserver , Destroyable { static createContentShareMeetingSessionConfigure ( configuration ) { const contentShareConfiguration = new MeetingSessionConfiguration ( ) ; contentShareConfiguration . meetingId = configuration . meetingId ; contentShareConfiguration . externalMeetingId = configuration . externalMeetingId ; contentShareConfiguration . urls = configuration . urls ; contentShareConfiguration . credentials = new MeetingSessionCredentials ( ) ; contentShareConfiguration . credentials . attendeeId = configuration . credentials . attendeeId + ContentShareConstants . Modality ; contentShareConfiguration . credentials . externalUserId = configuration . credentials . externalUserId ; contentShareConfiguration . credentials . joinToken = configuration . credentials . joinToken + ContentShareConstants . Modality ; return contentShareConfiguration ; } private observerQueue : Set < ContentShareObserver > = new Set < ContentShareObserver > ( ) ; private contentShareTile : VideoTile ; destroyed = false ; constructor ( private mediaStreamBroker , private contentAudioVideo , private attendeeAudioVideo ) { this . contentAudioVideo . addObserver ( this ) ; this . setupContentShareEvents ( ) ; } setContentAudioProfile ( audioProfile ) { this . contentAudioVideo . setAudioProfile ( audioProfile ) ; } async startContentShare ( stream ) { if ( ! stream ) { return ; } this . mediaStreamBroker . mediaStream = stream ; for ( let i = 0 ; i < this . mediaStreamBroker . mediaStream . getTracks ( ) . length ; i ++ ) { this . mediaStreamBroker . mediaStream . getTracks ( ) [ i ] . addEventListener ( 'ended' , ( ) => { this . stopContentShare ( ) ; } ) ; } this . contentAudioVideo . start ( ) ; if ( this . mediaStreamBroker . mediaStream . getVideoTracks ( ) . length > 0 ) { this . contentAudioVideo . videoTileController . startLocalVideoTile ( ) ; } } async startContentShareFromScreenCapture ( sourceId ? , frameRate ? ) { const mediaStream = await this . mediaStreamBroker . acquireScreenCaptureDisplayInputStream ( sourceId , frameRate ) ; await this . startContentShare ( mediaStream ) ; return mediaStream ; } pauseContentShare ( ) { if ( this . mediaStreamBroker . toggleMediaStream ( false ) ) { this . forEachContentShareObserver ( observer => { Maybe . of ( observer . contentShareDidPause ) . map ( f => f . call ( observer ) ) ; } ) ; } } unpauseContentShare ( ) { if ( this . mediaStreamBroker . toggleMediaStream ( true ) ) { this . forEachContentShareObserver ( observer => { Maybe . of ( observer . contentShareDidUnpause ) . map ( f => f . call ( observer ) ) ; } ) ; } } async destroy ( ) { if ( ! this . contentAudioVideo ) { return ; } this . destroyed = true ; this . contentAudioVideo . removeObserver ( this ) ; this . stopContentShare ( ) ; this . observerQueue . clear ( ) ; this . contentAudioVideo = undefined ; this . attendeeAudioVideo = undefined ; this . mediaStreamBroker = undefined ; } stopContentShare ( ) { this . contentAudioVideo . stop ( ) ; this . mediaStreamBroker . cleanup ( ) ; } addContentShareObserver ( observer ) { this . observerQueue . add ( observer ) ; } removeContentShareObserver ( observer ) { this . observerQueue . delete ( observer ) ; } forEachContentShareObserver ( observerFunc ) { for ( const observer of this . observerQueue ) { AsyncScheduler . nextTick ( ( ) => { if ( this . observerQueue . has ( observer ) ) { observerFunc ( observer ) ; } } ) ; } } audioVideoDidStop ( _sessionStatus ) { this . mediaStreamBroker . cleanup ( ) ; if ( this . contentShareTile ) { this . attendeeAudioVideo . videoTileController . removeVideoTile ( this . contentShareTile . id ( ) ) ; this . contentShareTile = null ; } this . forEachContentShareObserver ( observer => { Maybe . of ( observer . contentShareDidStop ) . map ( f => f . call ( observer ) ) ; } ) ; } private setupContentShareEvents ( ) { this . attendeeAudioVideo . realtimeController . realtimeSubscribeToAttendeeIdPresence ( ( attendeeId , present , _externalUserId , _dropped ) : void => { const isContentAttendee = new DefaultModality ( attendeeId ) . hasModality ( DefaultModality . MODALITY_CONTENT ) ; const isSelfAttendee = new DefaultModality ( attendeeId ) . base ( ) === this . attendeeAudioVideo . configuration . credentials . attendeeId ; if ( ! isContentAttendee || ! isSelfAttendee || ! present || this . contentShareTile ) { return ; } const stream = this . mediaStreamBroker . mediaStream ; if ( stream ?. getVideoTracks ( ) . length ) { this . contentShareTile = this . attendeeAudioVideo . videoTileController . addVideoTile ( ) ; const track = stream . getVideoTracks ( ) [ 0 ] ; let width , height ; if ( track . getSettings ) { const cap = track . getSettings ( ) ; width = cap . width as number ; height = cap . height as number ; } else { const cap = track . getCapabilities ( ) ; width = cap . width as number ; height = cap . height as number ; } this . contentShareTile . bindVideoStream ( this . contentAudioVideo . configuration . credentials . attendeeId , false , stream , width , height , null , this . contentAudioVideo . configuration . credentials . externalUserId ) ; } this . forEachContentShareObserver ( observer => { Maybe . of ( observer . contentShareDidStart ) . map ( f => f . call ( observer ) ) ; } ) ; } ) ; } }