2018-04-26 15:33:47 +02:00
/ *
2018-05-06 02:20:25 +02:00
* ( C ) Copyright 2017 - 2018 OpenVidu ( https : //openvidu.io/)
2018-04-26 15:33:47 +02:00
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*
* /
2018-05-08 13:01:34 +02:00
import { OpenVidu } from './OpenVidu' ;
import { Session } from './Session' ;
import { Stream } from './Stream' ;
2018-05-29 18:28:58 +02:00
import { StreamManager } from './StreamManager' ;
2018-04-26 15:33:47 +02:00
import { EventDispatcher } from '../OpenViduInternal/Interfaces/Public/EventDispatcher' ;
import { PublisherProperties } from '../OpenViduInternal/Interfaces/Public/PublisherProperties' ;
2018-05-23 15:01:40 +02:00
import { Event } from '../OpenViduInternal/Events/Event' ;
2018-04-26 15:33:47 +02:00
import { StreamEvent } from '../OpenViduInternal/Events/StreamEvent' ;
2018-07-03 15:35:08 +02:00
import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPropertyChangedEvent' ;
2018-04-26 15:33:47 +02:00
import { VideoElementEvent } from '../OpenViduInternal/Events/VideoElementEvent' ;
import { OpenViduError , OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError' ;
2018-05-08 13:01:34 +02:00
import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode' ;
2018-04-26 15:33:47 +02:00
2018-07-03 15:35:08 +02:00
import platform = require ( 'platform' ) ;
2018-04-26 15:33:47 +02:00
/ * *
* Packs local media streams . Participants can publish it to a session . Initialized with [ [ OpenVidu . initPublisher ] ] method
* /
2018-05-29 18:28:58 +02:00
export class Publisher extends StreamManager {
2018-04-26 15:33:47 +02:00
/ * *
* Whether the Publisher has been granted access to the requested input devices or not
* /
accessAllowed = false ;
2018-05-30 12:24:18 +02:00
/ * *
2018-06-01 14:39:38 +02:00
* Whether you have called [ [ Publisher . subscribeToRemote ] ] with value ` true ` or ` false ` ( * false * by default )
2018-05-30 12:24:18 +02:00
* /
isSubscribedToRemote = false ;
2018-04-26 15:33:47 +02:00
/ * *
* The [ [ Session ] ] to which the Publisher belongs
* /
session : Session ; // Initialized by Session.publish(Publisher)
2018-05-29 18:28:58 +02:00
private accessDenied = false ;
2018-04-26 15:33:47 +02:00
private properties : PublisherProperties ;
private permissionDialogTimeout : NodeJS.Timer ;
2018-07-03 15:35:08 +02:00
/ * *
* hidden
* /
openvidu : OpenVidu ;
/ * *
* @hidden
* /
videoReference : HTMLVideoElement ;
2018-04-26 15:33:47 +02:00
/ * *
* @hidden
* /
2018-07-03 15:35:08 +02:00
screenShareResizeInterval : NodeJS.Timer ;
/ * *
* @hidden
* /
constructor ( targEl : string | HTMLElement , properties : PublisherProperties , openvidu : OpenVidu ) {
2018-05-29 18:28:58 +02:00
super ( new Stream ( ( ! ! openvidu . session ) ? openvidu.session : new Session ( openvidu ) , { publisherProperties : properties , mediaConstraints : { } } ) , targEl ) ;
2018-04-26 15:33:47 +02:00
this . properties = properties ;
2018-07-03 15:35:08 +02:00
this . openvidu = openvidu ;
2018-04-26 15:33:47 +02:00
2018-07-05 17:50:49 +02:00
this . stream . ee . on ( 'local-stream-destroyed' , ( reason : string ) = > {
2018-07-09 15:45:20 +02:00
this . stream . isLocalStreamPublished = false ;
2018-04-26 15:33:47 +02:00
const streamEvent = new StreamEvent ( true , this , 'streamDestroyed' , this . stream , reason ) ;
2018-07-03 15:35:08 +02:00
this . emitEvent ( 'streamDestroyed' , [ streamEvent ] ) ;
streamEvent . callDefaultBehavior ( ) ;
2018-04-26 15:33:47 +02:00
} ) ;
}
2018-06-01 14:39:38 +02:00
2018-04-26 15:33:47 +02:00
/ * *
* Publish or unpublish the audio stream ( if available ) . Calling this method twice in a row passing same value will have no effect
2018-07-03 15:35:08 +02:00
*
* # # # # Events dispatched
*
* The [ [ Session ] ] object of the local participant will dispatch a ` streamPropertyChanged ` event with ` changedProperty ` set to ` "audioActive" ` and ` reason ` set to ` "publishAudio" `
* The [ [ Publisher ] ] object of the local participant will also dispatch the exact same event
*
* The [ [ Session ] ] object of every other participant connected to the session will dispatch a ` streamPropertyChanged ` event with ` changedProperty ` set to ` "audioActive" ` and ` reason ` set to ` "publishAudio" `
* The respective [ [ Subscriber ] ] object of every other participant receiving this Publisher ' s stream will also dispatch the exact same event
*
* See [ [ StreamPropertyChangedEvent ] ] to learn more .
*
2018-04-26 15:33:47 +02:00
* @param value ` true ` to publish the audio stream , ` false ` to unpublish it
* /
publishAudio ( value : boolean ) : void {
2018-07-03 15:35:08 +02:00
if ( this . stream . audioActive !== value ) {
this . stream . getMediaStream ( ) . getAudioTracks ( ) . forEach ( ( track ) = > {
track . enabled = value ;
} ) ;
this . session . openvidu . sendRequest (
'streamPropertyChanged' ,
{
streamId : this.stream.streamId ,
property : 'audioActive' ,
newValue : value ,
reason : 'publishAudio'
} ,
( error , response ) = > {
if ( error ) {
console . error ( "Error sending 'streamPropertyChanged' event" , error ) ;
} else {
this . session . emitEvent ( 'streamPropertyChanged' , [ new StreamPropertyChangedEvent ( this . session , this . stream , 'audioActive' , value , ! value , 'publishAudio' ) ] ) ;
this . emitEvent ( 'streamPropertyChanged' , [ new StreamPropertyChangedEvent ( this , this . stream , 'audioActive' , value , ! value , 'publishAudio' ) ] ) ;
}
} ) ;
this . stream . audioActive = value ;
console . info ( "'Publisher' has " + ( value ? 'published' : 'unpublished' ) + ' its audio stream' ) ;
}
2018-04-26 15:33:47 +02:00
}
2018-06-01 14:39:38 +02:00
2018-04-26 15:33:47 +02:00
/ * *
* Publish or unpublish the video stream ( if available ) . Calling this method twice in a row passing same value will have no effect
2018-07-03 15:35:08 +02:00
*
* # # # # Events dispatched
*
* The [ [ Session ] ] object of the local participant will dispatch a ` streamPropertyChanged ` event with ` changedProperty ` set to ` "videoActive" ` and ` reason ` set to ` "publishVideo" `
* The [ [ Publisher ] ] object of the local participant will also dispatch the exact same event
*
* The [ [ Session ] ] object of every other participant connected to the session will dispatch a ` streamPropertyChanged ` event with ` changedProperty ` set to ` "videoActive" ` and ` reason ` set to ` "publishVideo" `
* The respective [ [ Subscriber ] ] object of every other participant receiving this Publisher ' s stream will also dispatch the exact same event
*
* See [ [ StreamPropertyChangedEvent ] ] to learn more .
*
2018-04-26 15:33:47 +02:00
* @param value ` true ` to publish the video stream , ` false ` to unpublish it
* /
publishVideo ( value : boolean ) : void {
2018-07-03 15:35:08 +02:00
if ( this . stream . videoActive !== value ) {
this . stream . getMediaStream ( ) . getVideoTracks ( ) . forEach ( ( track ) = > {
track . enabled = value ;
} ) ;
this . session . openvidu . sendRequest (
'streamPropertyChanged' ,
{
streamId : this.stream.streamId ,
property : 'videoActive' ,
newValue : value ,
reason : 'publishVideo'
} ,
( error , response ) = > {
if ( error ) {
console . error ( "Error sending 'streamPropertyChanged' event" , error ) ;
} else {
this . session . emitEvent ( 'streamPropertyChanged' , [ new StreamPropertyChangedEvent ( this . session , this . stream , 'videoActive' , value , ! value , 'publishVideo' ) ] ) ;
this . emitEvent ( 'streamPropertyChanged' , [ new StreamPropertyChangedEvent ( this , this . stream , 'videoActive' , value , ! value , 'publishVideo' ) ] ) ;
}
} ) ;
this . stream . videoActive = value ;
console . info ( "'Publisher' has " + ( value ? 'published' : 'unpublished' ) + ' its video stream' ) ;
}
2018-04-26 15:33:47 +02:00
}
2018-06-01 14:39:38 +02:00
2018-04-26 15:33:47 +02:00
/ * *
2018-07-03 15:35:08 +02:00
* Call this method before [ [ Session . publish ] ] if you prefer to subscribe to your Publisher ' s remote stream instead of using the local stream , as any other user would do .
2018-04-26 15:33:47 +02:00
* /
2018-05-30 12:24:18 +02:00
subscribeToRemote ( value? : boolean ) : void {
value = ( value !== undefined ) ? value : true ;
this . isSubscribedToRemote = value ;
this . stream . subscribeToMyRemote ( value ) ;
2018-04-26 15:33:47 +02:00
}
/ * *
* See [ [ EventDispatcher . on ] ]
* /
2018-05-23 15:01:40 +02:00
on ( type : string , handler : ( event : Event ) = > void ) : EventDispatcher {
super . on ( type , handler ) ;
2018-04-26 15:33:47 +02:00
if ( type === 'streamCreated' ) {
2018-05-23 15:01:40 +02:00
if ( ! ! this . stream && this . stream . isLocalStreamPublished ) {
2018-07-03 15:35:08 +02:00
this . emitEvent ( 'streamCreated' , [ new StreamEvent ( false , this , 'streamCreated' , this . stream , '' ) ] ) ;
2018-04-26 15:33:47 +02:00
} else {
2018-05-29 18:28:58 +02:00
this . stream . ee . on ( 'stream-created-by-publisher' , ( ) = > {
2018-07-03 15:35:08 +02:00
this . emitEvent ( 'streamCreated' , [ new StreamEvent ( false , this , 'streamCreated' , this . stream , '' ) ] ) ;
2018-04-26 15:33:47 +02:00
} ) ;
}
}
if ( type === 'remoteVideoPlaying' ) {
2018-05-29 18:28:58 +02:00
if ( this . stream . displayMyRemote ( ) && this . videos [ 0 ] && this . videos [ 0 ] . video &&
this . videos [ 0 ] . video . currentTime > 0 &&
this . videos [ 0 ] . video . paused === false &&
this . videos [ 0 ] . video . ended === false &&
this . videos [ 0 ] . video . readyState === 4 ) {
2018-07-03 15:35:08 +02:00
this . emitEvent ( 'remoteVideoPlaying' , [ new VideoElementEvent ( this . videos [ 0 ] . video , this , 'remoteVideoPlaying' ) ] ) ;
2018-04-26 15:33:47 +02:00
}
}
if ( type === 'accessAllowed' ) {
2018-05-23 15:01:40 +02:00
if ( this . accessAllowed ) {
2018-07-03 15:35:08 +02:00
this . emitEvent ( 'accessAllowed' , [ ] ) ;
2018-04-26 15:33:47 +02:00
}
}
if ( type === 'accessDenied' ) {
2018-05-23 15:01:40 +02:00
if ( this . accessDenied ) {
2018-07-03 15:35:08 +02:00
this . emitEvent ( 'accessDenied' , [ ] ) ;
2018-04-26 15:33:47 +02:00
}
}
return this ;
}
/ * *
* See [ [ EventDispatcher . once ] ]
* /
2018-05-23 15:01:40 +02:00
once ( type : string , handler : ( event : Event ) = > void ) : Publisher {
super . once ( type , handler ) ;
2018-04-26 15:33:47 +02:00
if ( type === 'streamCreated' ) {
2018-05-23 15:01:40 +02:00
if ( ! ! this . stream && this . stream . isLocalStreamPublished ) {
2018-07-03 15:35:08 +02:00
this . emitEvent ( 'streamCreated' , [ new StreamEvent ( false , this , 'streamCreated' , this . stream , '' ) ] ) ;
2018-04-26 15:33:47 +02:00
} else {
2018-05-29 18:28:58 +02:00
this . stream . ee . once ( 'stream-created-by-publisher' , ( ) = > {
2018-07-03 15:35:08 +02:00
this . emitEvent ( 'streamCreated' , [ new StreamEvent ( false , this , 'streamCreated' , this . stream , '' ) ] ) ;
2018-04-26 15:33:47 +02:00
} ) ;
}
}
if ( type === 'remoteVideoPlaying' ) {
2018-05-29 18:28:58 +02:00
if ( this . stream . displayMyRemote ( ) && this . videos [ 0 ] && this . videos [ 0 ] . video &&
this . videos [ 0 ] . video . currentTime > 0 &&
this . videos [ 0 ] . video . paused === false &&
this . videos [ 0 ] . video . ended === false &&
this . videos [ 0 ] . video . readyState === 4 ) {
2018-07-03 15:35:08 +02:00
this . emitEvent ( 'remoteVideoPlaying' , [ new VideoElementEvent ( this . videos [ 0 ] . video , this , 'remoteVideoPlaying' ) ] ) ;
2018-04-26 15:33:47 +02:00
}
}
if ( type === 'accessAllowed' ) {
2018-05-23 15:01:40 +02:00
if ( this . accessAllowed ) {
2018-07-03 15:35:08 +02:00
this . emitEvent ( 'accessAllowed' , [ ] ) ;
2018-04-26 15:33:47 +02:00
}
}
if ( type === 'accessDenied' ) {
2018-05-23 15:01:40 +02:00
if ( this . accessDenied ) {
2018-07-03 15:35:08 +02:00
this . emitEvent ( 'accessDenied' , [ ] ) ;
2018-04-26 15:33:47 +02:00
}
}
return this ;
}
/* Hidden methods */
/ * *
* @hidden
* /
initialize ( ) : Promise < any > {
return new Promise ( ( resolve , reject ) = > {
const errorCallback = ( openViduError : OpenViduError ) = > {
2018-05-23 15:01:40 +02:00
this . accessDenied = true ;
this . accessAllowed = false ;
2018-04-26 15:33:47 +02:00
reject ( openViduError ) ;
} ;
const successCallback = ( mediaStream : MediaStream ) = > {
2018-05-23 15:01:40 +02:00
this . accessAllowed = true ;
this . accessDenied = false ;
2018-04-26 15:33:47 +02:00
2018-09-03 11:12:52 +02:00
if ( this . properties . audioSource instanceof MediaStreamTrack ) {
2018-04-26 15:33:47 +02:00
mediaStream . removeTrack ( mediaStream . getAudioTracks ( ) [ 0 ] ) ;
mediaStream . addTrack ( ( < MediaStreamTrack > this . properties . audioSource ) ) ;
}
2018-09-03 11:12:52 +02:00
if ( this . properties . videoSource instanceof MediaStreamTrack ) {
2018-04-26 15:33:47 +02:00
mediaStream . removeTrack ( mediaStream . getVideoTracks ( ) [ 0 ] ) ;
mediaStream . addTrack ( ( < MediaStreamTrack > this . properties . videoSource ) ) ;
}
// Apply PublisherProperties.publishAudio and PublisherProperties.publishVideo
if ( ! ! mediaStream . getAudioTracks ( ) [ 0 ] ) {
2018-07-19 17:31:30 +02:00
const enabled = ( this . stream . audioActive !== undefined && this . stream . audioActive !== null ) ? this . stream . audioActive : ! ! this . stream . outboundStreamOpts . publisherProperties . publishAudio ;
mediaStream . getAudioTracks ( ) [ 0 ] . enabled = enabled ;
2018-04-26 15:33:47 +02:00
}
if ( ! ! mediaStream . getVideoTracks ( ) [ 0 ] ) {
2018-07-19 17:31:30 +02:00
const enabled = ( this . stream . videoActive !== undefined && this . stream . videoActive !== null ) ? this . stream . videoActive : ! ! this . stream . outboundStreamOpts . publisherProperties . publishVideo ;
mediaStream . getVideoTracks ( ) [ 0 ] . enabled = enabled ;
2018-04-26 15:33:47 +02:00
}
2018-07-10 12:37:12 +02:00
this . videoReference = document . createElement ( 'video' ) ;
this . videoReference . srcObject = mediaStream ;
2018-04-26 15:33:47 +02:00
this . stream . setMediaStream ( mediaStream ) ;
2018-05-30 12:24:18 +02:00
if ( ! this . stream . displayMyRemote ( ) ) {
// When we are subscribed to our remote we don't still set the MediaStream object in the video elements to
// avoid early 'streamPlaying' event
this . stream . updateMediaStreamInVideos ( ) ;
}
2018-05-29 18:28:58 +02:00
if ( ! ! this . firstVideoElement ) {
this . createVideoElement ( this . firstVideoElement . targetElement , < VideoInsertMode > this . properties . insertMode ) ;
}
delete this . firstVideoElement ;
2018-04-26 15:33:47 +02:00
2018-07-04 12:25:56 +02:00
if ( this . stream . isSendVideo ( ) ) {
if ( ! this . stream . isSendScreen ( ) ) {
// With no screen share, video dimension can be set directly from MediaStream (getSettings)
// Orientation must be checked for mobile devices (width and height are reversed)
const { width , height } = mediaStream . getVideoTracks ( ) [ 0 ] . getSettings ( ) ;
if ( platform . name ! ! . toLowerCase ( ) . indexOf ( 'mobile' ) !== - 1 && ( window . innerHeight > window . innerWidth ) ) {
// Mobile portrait mode
this . stream . videoDimensions = {
width : height || 0 ,
height : width || 0
} ;
} else {
this . stream . videoDimensions = {
width : width || 0 ,
height : height || 0
} ;
}
this . stream . isLocalStreamReadyToPublish = true ;
this . stream . ee . emitEvent ( 'stream-ready-to-publish' , [ ] ) ;
2018-07-03 15:35:08 +02:00
} else {
2018-07-04 12:25:56 +02:00
// With screen share, video dimension must be got from a video element (onloadedmetadata event)
this . videoReference . onloadedmetadata = ( ) = > {
this . stream . videoDimensions = {
width : this.videoReference.videoWidth ,
height : this.videoReference.videoHeight
} ;
this . screenShareResizeInterval = setInterval ( ( ) = > {
const firefoxSettings = mediaStream . getVideoTracks ( ) [ 0 ] . getSettings ( ) ;
const newWidth = ( platform . name === 'Chrome' ) ? this . videoReference.videoWidth : firefoxSettings.width ;
const newHeight = ( platform . name === 'Chrome' ) ? this . videoReference.videoHeight : firefoxSettings.height ;
if ( this . stream . isLocalStreamPublished &&
( newWidth !== this . stream . videoDimensions . width ||
newHeight !== this . stream . videoDimensions . height ) ) {
const oldValue = { width : this.stream.videoDimensions.width , height : this.stream.videoDimensions.height } ;
this . stream . videoDimensions = {
width : newWidth || 0 ,
height : newHeight || 0
} ;
this . session . openvidu . sendRequest (
'streamPropertyChanged' ,
{
streamId : this.stream.streamId ,
property : 'videoDimensions' ,
newValue : JSON.stringify ( this . stream . videoDimensions ) ,
reason : 'screenResized'
} ,
( error , response ) = > {
if ( error ) {
console . error ( "Error sending 'streamPropertyChanged' event" , error ) ;
} else {
this . session . emitEvent ( 'streamPropertyChanged' , [ new StreamPropertyChangedEvent ( this . session , this . stream , 'videoDimensions' , this . stream . videoDimensions , oldValue , 'screenResized' ) ] ) ;
this . emitEvent ( 'streamPropertyChanged' , [ new StreamPropertyChangedEvent ( this , this . stream , 'videoDimensions' , this . stream . videoDimensions , oldValue , 'screenResized' ) ] ) ;
}
} ) ;
}
} , 500 ) ;
this . stream . isLocalStreamReadyToPublish = true ;
this . stream . ee . emitEvent ( 'stream-ready-to-publish' , [ ] ) ;
2018-07-03 15:35:08 +02:00
} ;
}
2018-07-04 12:25:56 +02:00
} else {
2018-07-03 15:35:08 +02:00
this . stream . isLocalStreamReadyToPublish = true ;
this . stream . ee . emitEvent ( 'stream-ready-to-publish' , [ ] ) ;
}
2018-04-26 15:33:47 +02:00
resolve ( ) ;
} ;
2018-09-03 11:12:52 +02:00
// Check if new constraints need to be generated. No constraints needed if
// - video track is given and no audio
// - audio track is given and no video
// - both video and audio tracks are given
if ( ( this . properties . videoSource instanceof MediaStreamTrack && ! this . properties . audioSource )
|| ( this . properties . audioSource instanceof MediaStreamTrack && ! this . properties . videoSource )
|| ( this . properties . videoSource instanceof MediaStreamTrack && this . properties . audioSource instanceof MediaStreamTrack ) ) {
const mediaStream = new MediaStream ( ) ;
if ( this . properties . videoSource instanceof MediaStreamTrack ) {
mediaStream . addTrack ( ( < MediaStreamTrack > this . properties . videoSource ) ) ;
}
if ( this . properties . audioSource instanceof MediaStreamTrack ) {
mediaStream . addTrack ( ( < MediaStreamTrack > this . properties . audioSource ) ) ;
}
// MediaStreamTracks are handled within callback - just call callback with new MediaStream() and let it handle the sources
successCallback ( mediaStream ) ;
// Return as we do not need to process further
return ;
}
2018-04-26 15:33:47 +02:00
this . openvidu . generateMediaConstraints ( this . properties )
. then ( constraints = > {
const outboundStreamOptions = {
mediaConstraints : constraints ,
publisherProperties : this.properties
} ;
this . stream . setOutboundStreamOptions ( outboundStreamOptions ) ;
const constraintsAux : MediaStreamConstraints = { } ;
2018-05-03 10:58:26 +02:00
const timeForDialogEvent = 1250 ;
2018-04-26 15:33:47 +02:00
2018-05-30 12:24:18 +02:00
if ( this . stream . isSendVideo ( ) || this . stream . isSendAudio ( ) ) {
const definedAudioConstraint = ( ( constraints . audio === undefined ) ? true : constraints . audio ) ;
constraintsAux . audio = this . stream . isSendScreen ( ) ? false : definedAudioConstraint ;
2018-04-26 15:33:47 +02:00
constraintsAux . video = constraints . video ;
let startTime = Date . now ( ) ;
this . setPermissionDialogTimer ( timeForDialogEvent ) ;
navigator . mediaDevices . getUserMedia ( constraintsAux )
2018-05-30 12:24:18 +02:00
. then ( mediaStream = > {
2018-04-26 15:33:47 +02:00
this . clearPermissionDialogTimer ( startTime , timeForDialogEvent ) ;
2018-05-30 12:24:18 +02:00
if ( this . stream . isSendScreen ( ) && this . stream . isSendAudio ( ) ) {
// When getting desktop as user media audio constraint must be false. Now we can ask for it if required
constraintsAux . audio = definedAudioConstraint ;
2018-04-26 15:33:47 +02:00
constraintsAux . video = false ;
startTime = Date . now ( ) ;
this . setPermissionDialogTimer ( timeForDialogEvent ) ;
navigator . mediaDevices . getUserMedia ( constraintsAux )
. then ( audioOnlyStream = > {
this . clearPermissionDialogTimer ( startTime , timeForDialogEvent ) ;
2018-05-30 12:24:18 +02:00
mediaStream . addTrack ( audioOnlyStream . getAudioTracks ( ) [ 0 ] ) ;
successCallback ( mediaStream ) ;
2018-04-26 15:33:47 +02:00
} )
. catch ( error = > {
this . clearPermissionDialogTimer ( startTime , timeForDialogEvent ) ;
2018-05-30 12:24:18 +02:00
let errorName , errorMessage ;
2018-04-26 15:33:47 +02:00
switch ( error . name . toLowerCase ( ) ) {
case 'notfounderror' :
errorName = OpenViduErrorName . INPUT_AUDIO_DEVICE_NOT_FOUND ;
errorMessage = error . toString ( ) ;
2018-05-30 12:24:18 +02:00
errorCallback ( new OpenViduError ( errorName , errorMessage ) ) ;
2018-04-26 15:33:47 +02:00
break ;
case 'notallowederror' :
2018-05-30 12:24:18 +02:00
errorName = OpenViduErrorName . DEVICE_ACCESS_DENIED ;
2018-04-26 15:33:47 +02:00
errorMessage = error . toString ( ) ;
2018-05-30 12:24:18 +02:00
errorCallback ( new OpenViduError ( errorName , errorMessage ) ) ;
2018-04-26 15:33:47 +02:00
break ;
case 'overconstrainederror' :
if ( error . constraint . toLowerCase ( ) === 'deviceid' ) {
errorName = OpenViduErrorName . INPUT_AUDIO_DEVICE_NOT_FOUND ;
2018-05-30 12:24:18 +02:00
errorMessage = "Audio input device with deviceId '" + ( < ConstrainDOMStringParameters > ( < MediaTrackConstraints > constraints . video ) . deviceId ! ! ) . exact + "' not found" ;
2018-04-26 15:33:47 +02:00
} else {
errorName = OpenViduErrorName . PUBLISHER_PROPERTIES_ERROR ;
errorMessage = "Audio input device doesn't support the value passed for constraint '" + error . constraint + "'" ;
}
2018-05-30 12:24:18 +02:00
errorCallback ( new OpenViduError ( errorName , errorMessage ) ) ;
break ;
2018-04-26 15:33:47 +02:00
}
} ) ;
} else {
2018-05-30 12:24:18 +02:00
successCallback ( mediaStream ) ;
2018-04-26 15:33:47 +02:00
}
} )
. catch ( error = > {
this . clearPermissionDialogTimer ( startTime , timeForDialogEvent ) ;
2018-05-30 12:24:18 +02:00
let errorName , errorMessage ;
2018-04-26 15:33:47 +02:00
switch ( error . name . toLowerCase ( ) ) {
case 'notfounderror' :
2018-05-30 12:24:18 +02:00
navigator . mediaDevices . getUserMedia ( {
audio : false ,
video : constraints.video
} )
. then ( mediaStream = > {
mediaStream . getVideoTracks ( ) . forEach ( ( track ) = > {
track . stop ( ) ;
} ) ;
errorName = OpenViduErrorName . INPUT_AUDIO_DEVICE_NOT_FOUND ;
errorMessage = error . toString ( ) ;
errorCallback ( new OpenViduError ( errorName , errorMessage ) ) ;
} ) . catch ( e = > {
errorName = OpenViduErrorName . INPUT_VIDEO_DEVICE_NOT_FOUND ;
errorMessage = error . toString ( ) ;
errorCallback ( new OpenViduError ( errorName , errorMessage ) ) ;
} ) ;
2018-04-26 15:33:47 +02:00
break ;
case 'notallowederror' :
2018-05-30 12:24:18 +02:00
errorName = this . stream . isSendScreen ( ) ? OpenViduErrorName.SCREEN_CAPTURE_DENIED : OpenViduErrorName.DEVICE_ACCESS_DENIED ;
2018-04-26 15:33:47 +02:00
errorMessage = error . toString ( ) ;
2018-05-30 12:24:18 +02:00
errorCallback ( new OpenViduError ( errorName , errorMessage ) ) ;
2018-04-26 15:33:47 +02:00
break ;
case 'overconstrainederror' :
2018-05-30 12:24:18 +02:00
navigator . mediaDevices . getUserMedia ( {
audio : false ,
video : constraints.video
} )
. then ( mediaStream = > {
mediaStream . getVideoTracks ( ) . forEach ( ( track ) = > {
track . stop ( ) ;
} ) ;
if ( error . constraint . toLowerCase ( ) === 'deviceid' ) {
2018-05-30 16:36:27 +02:00
errorName = OpenViduErrorName . INPUT_AUDIO_DEVICE_NOT_FOUND ;
errorMessage = "Audio input device with deviceId '" + ( < ConstrainDOMStringParameters > ( < MediaTrackConstraints > constraints . audio ) . deviceId ! ! ) . exact + "' not found" ;
2018-05-30 12:24:18 +02:00
} else {
errorName = OpenViduErrorName . PUBLISHER_PROPERTIES_ERROR ;
2018-05-30 16:36:27 +02:00
errorMessage = "Audio input device doesn't support the value passed for constraint '" + error . constraint + "'" ;
2018-05-30 12:24:18 +02:00
}
errorCallback ( new OpenViduError ( errorName , errorMessage ) ) ;
} ) . catch ( e = > {
if ( error . constraint . toLowerCase ( ) === 'deviceid' ) {
2018-05-30 16:36:27 +02:00
errorName = OpenViduErrorName . INPUT_VIDEO_DEVICE_NOT_FOUND ;
errorMessage = "Video input device with deviceId '" + ( < ConstrainDOMStringParameters > ( < MediaTrackConstraints > constraints . video ) . deviceId ! ! ) . exact + "' not found" ;
2018-05-30 12:24:18 +02:00
} else {
errorName = OpenViduErrorName . PUBLISHER_PROPERTIES_ERROR ;
2018-05-30 16:36:27 +02:00
errorMessage = "Video input device doesn't support the value passed for constraint '" + error . constraint + "'" ;
2018-05-30 12:24:18 +02:00
}
errorCallback ( new OpenViduError ( errorName , errorMessage ) ) ;
} ) ;
2018-04-26 15:33:47 +02:00
break ;
}
} ) ;
} else {
reject ( new OpenViduError ( OpenViduErrorName . NO_INPUT_SOURCE_SET ,
"Properties 'audioSource' and 'videoSource' cannot be set to false or null at the same time when calling 'OpenVidu.initPublisher'" ) ) ;
}
} )
. catch ( ( error : OpenViduError ) = > {
errorCallback ( error ) ;
} ) ;
} ) ;
}
2018-05-30 16:36:27 +02:00
/ * *
* @hidden
* /
reestablishStreamPlayingEvent() {
if ( this . ee . getListeners ( 'streamPlaying' ) . length > 0 ) {
this . addPlayEventToFirstVideo ( ) ;
}
}
2018-04-26 15:33:47 +02:00
/* Private methods */
private setPermissionDialogTimer ( waitTime : number ) : void {
this . permissionDialogTimeout = setTimeout ( ( ) = > {
2018-07-03 15:35:08 +02:00
this . emitEvent ( 'accessDialogOpened' , [ ] ) ;
2018-04-26 15:33:47 +02:00
} , waitTime ) ;
}
private clearPermissionDialogTimer ( startTime : number , waitTime : number ) : void {
clearTimeout ( this . permissionDialogTimeout ) ;
if ( ( Date . now ( ) - startTime ) > waitTime ) {
// Permission dialog was shown and now is closed
2018-07-03 15:35:08 +02:00
this . emitEvent ( 'accessDialogClosed' , [ ] ) ;
2018-04-26 15:33:47 +02:00
}
}
}