diff --git a/openvidu-browser/src/main/resources/ts/OpenVidu/OpenVidu.ts b/openvidu-browser/src/main/resources/ts/OpenVidu/OpenVidu.ts index 41080b55..925ab8d6 100644 --- a/openvidu-browser/src/main/resources/ts/OpenVidu/OpenVidu.ts +++ b/openvidu-browser/src/main/resources/ts/OpenVidu/OpenVidu.ts @@ -18,7 +18,7 @@ import { Session, SessionOptions } from './Session'; import { Stream } from './Stream'; import * as RpcBuilder from 'kurento-jsonrpc'; -export type Callback = ( error?: any, openVidu?: T ) => void; +export type Callback = (error?: any, openVidu?: T) => void; export class OpenVidu { @@ -28,9 +28,9 @@ export class OpenVidu { private callback: Callback; private camera: Stream; private remoteStreams: Stream[] = []; - - constructor( private wsUri: string ) { - if(this.wsUri.charAt(wsUri.length-1) != '/'){ + + constructor(private wsUri: string) { + if (this.wsUri.charAt(wsUri.length - 1) != '/') { this.wsUri += '/'; } this.wsUri += 'room'; @@ -58,19 +58,17 @@ export class OpenVidu { console.log("Error accessing the camera"); } else { - this.camera.playOnlyVideo(parentId, null); - this.camera.isReady = true; - this.camera.emitStreamReadyEvent(); + this.cameraReady(camera!, parentId); } }); return this.camera; } else { this.camera.requestCameraAccess((error, camera) => { - if (error){ + if (error) { callback(error); } else { - this.camera.playOnlyVideo(parentId, null); + this.cameraReady(camera!, parentId); callback(undefined); } }); @@ -78,6 +76,13 @@ export class OpenVidu { } } + cameraReady(camera: Stream, parentId: string) { + this.camera = camera; + this.camera.playOnlyVideo(parentId, null); + this.camera.isReady = true; + this.camera.emitStreamReadyEvent(); + } + initPublisher(cameraOptions: any, callback) { console.log("Publisher initialized!"); @@ -105,14 +110,14 @@ export class OpenVidu { return this.session; } - connect( callback: Callback ): void { + connect(callback: Callback): void { this.callback = callback; - this.initJsonRpcClient( this.wsUri ); + this.initJsonRpcClient(this.wsUri); } - private initJsonRpcClient( wsUri: string ): void { + private initJsonRpcClient(wsUri: string): void { let config = { heartbeat: 3000, @@ -120,177 +125,181 @@ export class OpenVidu { ws: { uri: wsUri, useSockJS: false, - onconnected: this.connectCallback.bind( this ), - ondisconnect: this.disconnectCallback.bind( this ), - onreconnecting: this.reconnectingCallback.bind( this ), - onreconnected: this.reconnectedCallback.bind( this ) + onconnected: this.connectCallback.bind(this), + ondisconnect: this.disconnectCallback.bind(this), + onreconnecting: this.reconnectingCallback.bind(this), + onreconnected: this.reconnectedCallback.bind(this) }, rpc: { requestTimeout: 15000, //notifications - participantJoined: this.onParticipantJoined.bind( this ), - participantPublished: this.onParticipantPublished.bind( this ), - participantUnpublished: this.onParticipantLeft.bind( this ), - participantLeft: this.onParticipantLeft.bind( this ), - participantEvicted: this.onParticipantEvicted.bind( this ), - sendMessage: this.onNewMessage.bind( this ), - iceCandidate: this.iceCandidateEvent.bind( this ), - mediaError: this.onMediaError.bind( this ), - custonNotification: this.customNotification.bind( this ) + participantJoined: this.onParticipantJoined.bind(this), + participantPublished: this.onParticipantPublished.bind(this), + participantUnpublished: this.onParticipantLeft.bind(this), + participantLeft: this.onParticipantLeft.bind(this), + participantEvicted: this.onParticipantEvicted.bind(this), + sendMessage: this.onNewMessage.bind(this), + iceCandidate: this.iceCandidateEvent.bind(this), + mediaError: this.onMediaError.bind(this), + custonNotification: this.customNotification.bind(this) } }; - this.jsonRpcClient = new RpcBuilder.clients.JsonRpcClient( config ); + this.jsonRpcClient = new RpcBuilder.clients.JsonRpcClient(config); } - private customNotification( params ) { - if ( this.isRoomAvailable() ) { - this.session.emitEvent( "custom-message-received", [{ params: params }] ); + private customNotification(params) { + if (this.isRoomAvailable()) { + this.session.emitEvent("custom-message-received", [{ params: params }]); } } - private connectCallback( error ) { - if ( error ) { - this.callback( error ); + private connectCallback(error) { + if (error) { + this.callback(error); } else { - this.callback( null ); + this.callback(null); } } private isRoomAvailable() { - if ( this.session !== undefined && this.session instanceof Session ) { + if (this.session !== undefined && this.session instanceof Session) { return true; } else { - console.warn( 'Room instance not found' ); + console.warn('Room instance not found'); return false; } } private disconnectCallback() { - console.log( 'Websocket connection lost' ); - if ( this.isRoomAvailable() ) { + console.log('Websocket connection lost'); + if (this.isRoomAvailable()) { this.session.onLostConnection(); } else { - alert( 'Connection error. Please reload page.' ); + alert('Connection error. Please reload page.'); } } private reconnectingCallback() { - console.log( 'Websocket connection lost (reconnecting)' ); - if ( this.isRoomAvailable() ) { + console.log('Websocket connection lost (reconnecting)'); + if (this.isRoomAvailable()) { this.session.onLostConnection(); } else { - alert( 'Connection error. Please reload page.' ); + alert('Connection error. Please reload page.'); } } private reconnectedCallback() { - console.log( 'Websocket reconnected' ); + console.log('Websocket reconnected'); } - private onParticipantJoined( params ) { - if ( this.isRoomAvailable() ) { - this.session.onParticipantJoined( params ); + private onParticipantJoined(params) { + if (this.isRoomAvailable()) { + this.session.onParticipantJoined(params); } } - private onParticipantPublished( params ) { - if ( this.isRoomAvailable() ) { - this.session.onParticipantPublished( params ); + private onParticipantPublished(params) { + if (this.isRoomAvailable()) { + this.session.onParticipantPublished(params); } } - private onParticipantLeft( params ) { - if ( this.isRoomAvailable() ) { - this.session.onParticipantLeft( params ); + private onParticipantLeft(params) { + if (this.isRoomAvailable()) { + this.session.onParticipantLeft(params); } } - private onParticipantEvicted( params ) { - if ( this.isRoomAvailable() ) { - this.session.onParticipantEvicted( params ); + private onParticipantEvicted(params) { + if (this.isRoomAvailable()) { + this.session.onParticipantEvicted(params); } } - private onNewMessage( params ) { - if ( this.isRoomAvailable() ) { - this.session.onNewMessage( params ); + private onNewMessage(params) { + if (this.isRoomAvailable()) { + this.session.onNewMessage(params); } } - private iceCandidateEvent( params ) { - if ( this.isRoomAvailable() ) { - this.session.recvIceCandidate( params ); + private iceCandidateEvent(params) { + if (this.isRoomAvailable()) { + this.session.recvIceCandidate(params); } } - private onRoomClosed( params ) { - if ( this.isRoomAvailable() ) { - this.session.onRoomClosed( params ); + private onRoomClosed(params) { + if (this.isRoomAvailable()) { + this.session.onRoomClosed(params); } } - private onMediaError( params ) { - if ( this.isRoomAvailable() ) { - this.session.onMediaError( params ); + private onMediaError(params) { + if (this.isRoomAvailable()) { + this.session.onMediaError(params); } } - setRpcParams( params: any ) { + setRpcParams(params: any) { this.rpcParams = params; } - sendRequest( method, params, callback?) { + sendRequest(method, params, callback?) { - if ( params && params instanceof Function ) { + if (params && params instanceof Function) { callback = params; params = undefined; } params = params || {}; - if ( this.rpcParams && this.rpcParams !== null && this.rpcParams !== undefined ) { - for ( let index in this.rpcParams ) { - if ( this.rpcParams.hasOwnProperty( index ) ) { + if (this.rpcParams && this.rpcParams !== null && this.rpcParams !== undefined) { + for (let index in this.rpcParams) { + if (this.rpcParams.hasOwnProperty(index)) { params[index] = this.rpcParams[index]; - console.log( 'RPC param added to request {' + index + ': ' + this.rpcParams[index] + '}' ); + console.log('RPC param added to request {' + index + ': ' + this.rpcParams[index] + '}'); } } } - console.log( 'Sending request: { method:"' + method + '", params: ' + JSON.stringify( params ) + ' }' ); + console.log('Sending request: { method:"' + method + '", params: ' + JSON.stringify(params) + ' }'); - this.jsonRpcClient.send( method, params, callback ); + this.jsonRpcClient.send(method, params, callback); } - close( forced ) { - if ( this.isRoomAvailable() ) { - this.session.leave( forced, this.jsonRpcClient ); + close(forced) { + if (this.isRoomAvailable()) { + this.session.leave(forced, this.jsonRpcClient); } }; - disconnectParticipant( stream ) { - if ( this.isRoomAvailable() ) { - this.session.disconnect( stream ); + disconnectParticipant(stream) { + if (this.isRoomAvailable()) { + this.session.disconnect(stream); } } getCamera(options?) { - if(this.camera){ + if (this.camera) { return this.camera; } - + options = options || { audio: true, video: true, - data: true + data: true, + mediaConstraints: { + audio: true, + video: { width: { ideal: 1280 } } + } } options.participant = this.session.getLocalParticipant(); - this.camera = new Stream( this, true, this.session, options ); + this.camera = new Stream(this, true, this.session, options); return this.camera; }; @@ -308,38 +317,38 @@ export class OpenVidu { };*/ //CHAT - sendMessage( room, user, message ) { - this.sendRequest( 'sendMessage', { + sendMessage(room, user, message) { + this.sendRequest('sendMessage', { message: message, userMessage: user, roomMessage: room - }, function( error, response ) { - if ( error ) { - console.error( error ); + }, function (error, response) { + if (error) { + console.error(error); } }); }; - sendCustomRequest( params, callback ) { - this.sendRequest( 'customRequest', params, callback ); + sendCustomRequest(params, callback) { + this.sendRequest('customRequest', params, callback); }; - toggleLocalVideoTrack(activate: boolean){ + toggleLocalVideoTrack(activate: boolean) { this.getCamera().getWebRtcPeer().videoEnabled = activate; } - toggleLocalAudioTrack(activate: boolean){ + toggleLocalAudioTrack(activate: boolean) { this.getCamera().getWebRtcPeer().audioEnabled = activate; } publishLocalVideoAudio() { this.toggleLocalVideoTrack(true); - this.toggleLocalAudioTrack(true); + this.toggleLocalAudioTrack(true); } - + unpublishLocalVideoAudio() { this.toggleLocalVideoTrack(false); this.toggleLocalAudioTrack(false); diff --git a/openvidu-browser/src/main/resources/ts/OpenVidu/Stream.ts b/openvidu-browser/src/main/resources/ts/OpenVidu/Stream.ts index 34d52bd5..8af25db7 100644 --- a/openvidu-browser/src/main/resources/ts/OpenVidu/Stream.ts +++ b/openvidu-browser/src/main/resources/ts/OpenVidu/Stream.ts @@ -434,7 +434,7 @@ export class Stream { if (this.isReady) { this.initWebRtcPeer(this.publishVideoCallback); } else { - this.addEventListener('stream-ready', streamEvent => { + this.ee.once('stream-ready', streamEvent => { this.publish(); }); } diff --git a/openvidu-browser/src/main/resources/ts/OpenViduTokBox/OpenViduTokBox.ts b/openvidu-browser/src/main/resources/ts/OpenViduTokBox/OpenViduTokBox.ts index defbc3bc..da8b4b8f 100644 --- a/openvidu-browser/src/main/resources/ts/OpenViduTokBox/OpenViduTokBox.ts +++ b/openvidu-browser/src/main/resources/ts/OpenViduTokBox/OpenViduTokBox.ts @@ -38,8 +38,23 @@ export class OpenViduTokBox { } } - initPublisher(parentId: string, cameraOptions: any): PublisherTokBox { - return new PublisherTokBox(this.openVidu.initPublisherTagged(parentId, cameraOptions)); + initPublisher(parentId: string, cameraOptions: any): PublisherTokBox; + initPublisher(parentId: string, cameraOptions: any, callback: any): PublisherTokBox; + + initPublisher(parentId: string, cameraOptions: any, callback?): PublisherTokBox { + if (!("audio" in cameraOptions && "data" in cameraOptions && "mediaConstraints" in cameraOptions && + "video" in cameraOptions && (Object.keys(cameraOptions).length === 4))) { + cameraOptions = { + audio: true, + video: true, + data: true, + mediaConstraints: { + audio: true, + video: { width: { ideal: 1280 } } + } + } + } + return new PublisherTokBox(this.openVidu.initPublisherTagged(parentId, cameraOptions, callback)); } } diff --git a/openvidu-browser/src/main/resources/ts/OpenViduTokBox/PublisherTokBox.ts b/openvidu-browser/src/main/resources/ts/OpenViduTokBox/PublisherTokBox.ts index e3e5661e..ade5549f 100644 --- a/openvidu-browser/src/main/resources/ts/OpenViduTokBox/PublisherTokBox.ts +++ b/openvidu-browser/src/main/resources/ts/OpenViduTokBox/PublisherTokBox.ts @@ -13,8 +13,16 @@ export class PublisherTokBox { stream: Stream; - constructor(stream: Stream) { + constructor(stream: Stream) { this.stream = stream; } + publishAudio(value: boolean) { + this.stream.getWebRtcPeer().audioEnabled = value; + } + + publishVideo(value: boolean) { + this.stream.getWebRtcPeer().videoEnabled = value; + } + } diff --git a/openvidu-sample-app/src/main/resources/frontend/src/app/components/video-session/video-session.component.html b/openvidu-sample-app/src/main/resources/frontend/src/app/components/video-session/video-session.component.html index 81b96291..947ff915 100644 --- a/openvidu-sample-app/src/main/resources/frontend/src/app/components/video-session/video-session.component.html +++ b/openvidu-sample-app/src/main/resources/frontend/src/app/components/video-session/video-session.component.html @@ -5,5 +5,5 @@ {{audioIcon}}

{{lesson?.title}}

-
-
\ No newline at end of file +
+
\ No newline at end of file diff --git a/openvidu-sample-app/src/main/resources/frontend/src/app/components/video-session/video-session.component.ts b/openvidu-sample-app/src/main/resources/frontend/src/app/components/video-session/video-session.component.ts index c07cbe5d..cb8b5be4 100644 --- a/openvidu-sample-app/src/main/resources/frontend/src/app/components/video-session/video-session.component.ts +++ b/openvidu-sample-app/src/main/resources/frontend/src/app/components/video-session/video-session.component.ts @@ -18,13 +18,12 @@ export class VideoSessionComponent implements OnInit { OV: OpenViduTokBox; session: SessionTokBox; + publisher: PublisherTokBox; sessionId: string; token: string; cameraOptions: any; - localParentId: string = 'local-stream'; - remoteParentId: string = 'remote-streams'; localVideoActivated: boolean; localAudioActivated: boolean; @@ -45,29 +44,37 @@ export class VideoSessionComponent implements OnInit { // 1) Initialize OpenVidu and your Session this.OV = new OpenViduTokBox("wss://" + location.hostname + ":8443/"); - this.session = this.OV.initSession(this.sessionId); + this.session = this.OV.initSession("apikey", this.sessionId); // 2) Specify the actions when events take place this.session.on('streamCreated', (event) => { - console.warn("Stream created:"); - console.warn(event.stream); - this.session.subscribe(event.stream, this.remoteParentId); + this.session.subscribe(event.stream, 'subscriber', { + insertMode: 'append', + width: '100%', + height: '100%' + }); }); // 3) Connect to the session this.session.connect(this.token, (error) => { + + // If the connection is successful, initialize a publisher and publish to the session if (!error) { + // 4) Get your own camera stream with the desired resolution and publish it, only if the user is supposed to do so - let publisher = this.OV.initPublisher(this.localParentId, this.cameraOptions); + this.publisher = this.OV.initPublisher('publisher', { + insertMode: 'append', + width: '100%', + height: '100%' + }); + // 5) Publish your stream - this.session.publish(publisher); - } - else { - return console.log("There was an error: " + error); - } + this.session.publish(this.publisher); + } else { + console.log('There was an error connecting to the session:', error.code, error.message); + } }); - } @@ -142,6 +149,51 @@ export class VideoSessionComponent implements OnInit { content.style.overflow = scroll; } + toggleLocalVideo() { + this.localVideoActivated = !this.localVideoActivated; + this.publisher.publishVideo(this.localVideoActivated); + this.videoIcon = this.localVideoActivated ? 'videocam' : 'videocam_off'; + } + + toggleLocalAudio() { + this.localAudioActivated = !this.localAudioActivated; + this.publisher.publishAudio(this.localAudioActivated); + this.audioIcon = this.localAudioActivated ? 'mic' : 'mic_off'; + } + + toggleFullScreen() { + let document: any = window.document; + let fs = document.getElementsByTagName('html')[0]; + if (!document.fullscreenElement && + !document.mozFullScreenElement && + !document.webkitFullscreenElement && + !document.msFullscreenElement) { + console.log("enter FULLSCREEN!"); + this.fullscreenIcon = 'fullscreen_exit'; + if (fs.requestFullscreen) { + fs.requestFullscreen(); + } else if (fs.msRequestFullscreen) { + fs.msRequestFullscreen(); + } else if (fs.mozRequestFullScreen) { + fs.mozRequestFullScreen(); + } else if (fs.webkitRequestFullscreen) { + fs.webkitRequestFullscreen(); + } + } else { + console.log("exit FULLSCREEN!"); + this.fullscreenIcon = 'fullscreen'; + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.msExitFullscreen) { + document.msExitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } + } + } + exitFullScreen() { let document: any = window.document; let fs = document.getElementsByTagName('html')[0]; diff --git a/openvidu-sample-app/src/main/resources/frontend/src/styles.css b/openvidu-sample-app/src/main/resources/frontend/src/styles.css index c7e0e13c..1ee91316 100644 --- a/openvidu-sample-app/src/main/resources/frontend/src/styles.css +++ b/openvidu-sample-app/src/main/resources/frontend/src/styles.css @@ -66,21 +66,21 @@ md-icon:hover { display: inline-block; } -#local-stream { +#publisher { position: absolute; width: 100%; } -#local-stream video { +#publisher video { width: 100%; } -#remote-streams { +#subscriber { position: absolute; bottom: 0; } -#remote-streams video { +#subscriber video { width: 350px; }