stream/screen.js

ModuleBase.define("Screen", ["Base", "Error", "ScreenAudio"], function(Base,Error,ScreenAudio) {

	/**
	 * @desc 桌面共享Screen构造函数。
	 * @constructor
	 * @alias Screen
	 * @param {String} id - 设备Id
	 * @param {String} name - 设备名称
	 */
	class Screen extends Base {
		
		constructor(id, name, roomHandle) {
		    super(id, name);
		
			this.roomHandle = roomHandle;
			this.level;
			this.description;
			this.resolution = {
				width: avdEngineHandle.defaultScreenParamsWidth,
				height: avdEngineHandle.defaultScreenParamsHeight
			};
			this.frameRate = avdEngineHandle.defaultScreenParamsFrameRate;
			
			//通过分辨率宽高计算得出的最大带宽值
			this.maxBandwidth = null;
			
			//应用层客户调用接口自行设置的最大带宽值
			this.clientSetMaxBandwidth = null;
			
			this.extensionFlag;
			
			this.ipc = null;
			
			this.displaySurface = ScreenDisplaySurface.monitor; //桌面共享弹窗显示内容选项
			
			// chrome71及以后就支持displaySurface参数,但设置后未生效,96版本才开始生效。在115的时候可以指定为默认高亮“整个屏幕”
			if(avdEngineHandle.isChrome && avdEngineHandle.majorVersion < 96){
				this.displaySurface = '';
			}

			this.screenAudio = null;

			this.screenAudioEnabled = false; // 是否开启屏幕共享音频,默认false

			this.openTimer = null;

			this.unpublishTimer = null;

			this.subscribleTimer = null;

			this.unsubscribleTimer = null;

			this.videoStreamControlTimer = null;

		};
	
	/**
	 * @desc 设置桌面共享弹窗显示内容选项,chrome71及以后就支持displaySurface参数,但设置后未生效,96版本才开始真正生效。
	 * @param {ScreenDisplaySurface} screenDisplaySurface - 桌面共享弹窗显示内容选项(枚举型),默认值为ScreenDisplaySurface.monitor
	 * 
	 * @example 
	 * screen.setDisplaySurface(ScreenDisplaySurface.monitor);
	 */
	setDisplaySurface = function(screenDisplaySurface) {
		this.displaySurface = screenDisplaySurface;
		if(avdEngineHandle.isChrome && avdEngineHandle.majorVersion < 96){
			this.displaySurface = '';
		}
	};
	
	
	/**
	 * @desc 获取当前桌面共享弹窗显示内容选项
	 */
	getDisplaySurface = function() {
		return this.displaySurface;
	};


	/**
	 * @desc 设置桌面共享的优先级别
	 * @param {int} level -优先级别 
	 */
	setLevel = function(level) {
		this.level = level;
	};


	/**
	 * @desc 设置备注
	 * @param {String} description - 备注 
	 */
	setDescription = function(description) {
		this.description = description;
	};


	/**
	 * @desc 设置分辨率
	 * @param {int} width- 分辨率宽
	 * @param {int} height- 分辨率高
	 */
	setResolution = function(width, height) {
		var resolutionObject = {};
		resolutionObject.width = width;
		resolutionObject.height = height;
		this.resolution = resolutionObject;
	};


	/**
	 * @desc 设置帧率
	 * @param {int} frameRate - 帧率
	 */
	setFrameRate = function(frameRate) {
		this.frameRate = frameRate;
	};


	/**
	 * @desc 预览桌面共享,只能获取桌面共享流后或发布后操作后才能调用
	 * @param {Object} element - 视频控件
	 */
	preview = function(element) {
		log.info("===screen.preview()");
		var self = this;
		if(element){
			self.element = element;
		    self.element.srcObject = self.getNewStreamByTrack();
		}
	};
	
	
	/**
	 * @desc 获取桌面共享流
	 * @ignore
	 */
	getDisplayMedia = function(){
		log.info("===screen.getDisplayMedia()");
		var deferred = when.defer();
		
		var self = this;
		
		if(self.status == StreamStatus.published) {
			deferred.resolve();
		} else {
			if(navigator.mediaDevices.getDisplayMedia){
                    var displayMediaConstrains = {};
                    if(avdEngineHandle.isChrome){
                        // 宽高约束默认ideal,getDisplayMedia不支持min、max、exact约束
                        displayMediaConstrains.video = {
                            displaySurface: self.displaySurface,
                            frameRate: self.frameRate,
                            width: {
                                ideal: self.resolution.width
                            },
                            height: {
                                ideal: self.resolution.height
                            }
                        }
                        displayMediaConstrains.audio = true;
                    }
					
					if(self.displaySurface == ScreenDisplaySurface.preferCurrentTab){
						 if(avdEngineHandle.isChrome){
							 if(avdEngineHandle.majorVersion >=96){
								  delete displayMediaConstrains.video.displaySurface;
								  displayMediaConstrains.preferCurrentTab = true;
							 }else{
								  displayMediaConstrains.video.displaySurface = '' ;
							 }
						 } else{
							displayMediaConstrains.video.displaySurface = ScreenDisplaySurface.monitor;
						 } 
					}
					log.debug("===screen.getDisplayMedia(),displayMediaConstrains:"+ JSON.stringify(displayMediaConstrains));
					
			        navigator.mediaDevices.getDisplayMedia(displayMediaConstrains).then(function(stream){
						if(stream) {
							self.track = stream.getVideoTracks()[0];
                            var audioEnable = false;
                            // 如果打开了屏幕音频开关
                            if(stream && stream.getAudioTracks != undefined){       
                                var tempAudioTrack = stream.getAudioTracks()[0];
                                if(tempAudioTrack){
                                    if(self.screenAudio){
                                        self.screenAudio.track = tempAudioTrack;
                                        audioEnable = true;
                                    }
                                }
                            }
							deferred.resolve({stream: stream, audioEnable: audioEnable});
						}
					}).catch(function(error) {
                        log.error("===screen.publish(),Unable to acquire screen capture", error.name+",ownerId:"+self.ownerId);
                        var Error = ModuleBase.use(ModulesEnum.error);
                        var errorObj;
                        if(error.name == 'NotSupportedError'){
                            errorObj = new Error(ErrorConstant.navigatorDisplayMediaError_notSupportedError);
                        }else if(error.name == 'OverconstrainedError'){
                            errorObj = new Error(ErrorConstant.navigatorDisplayMediaError_overconstrainedError);
                        }else if(error.name == 'NotAllowedError'){
                            errorObj = new Error(ErrorConstant.navigatorDisplayMediaError_notAllowedError);
                        }else{
                            errorObj = new Error(ErrorConstant.navigatorDisplayMediaError_unknown);
                        }
                        deferred.reject(errorObj);
                    }); 		
			}else{
				log.debug("===screen.getDisplayMedia(),不支持 navigator.mediaDevices.getDisplayMedia.");
				avdEngineHandle.loggerReport.error("===screen.getDisplayMedia(),nonsupport navigator.mediaDevices.getDisplayMedia.");
		    }					
		}
		return deferred.promise;
	}


	/**
	 * @desc 发布桌面共享。
	 * @async
	 * @param {Object} displayMediaStream - 待发布的桌面共享流,可以为空。当空时,会弹出桌面共享选择应用框选择共享的内容。
	 */
	publish = function(displayMediaStream) {
		log.info("===screen.publish()...");
		var deferred = when.defer();
		
		var self = this;

        if(self.roomHandle.roomJoinState != RoomStateEnum.CONNECTED){
            var errObj = ErrorConstant.room_state_invalid
            errObj.message += ("(State: "+ self.roomHandle.roomJoinState +")")
            var err = new Error(errObj);
            log.debug("===video publish() 发布视频流异常, room state: " + self.roomHandle.roomJoinState);
            deferred.reject(err);
            return;
        }
       
		if(self.status == StreamStatus.published) {
			   deferred.resolve();
		} else {
			   if(!displayMediaStream){
				    self.getDisplayMedia().then(function(displayMediaResolved){
						 self.publishInner(displayMediaResolved.stream).then(function(){
                            if(displayMediaResolved.audioEnable){
                                self.screenAudio.publish().then(function(){
                                    deferred.resolve();        
                                })
                            }else{
                                deferred.resolve(); 
                            }
						 }).otherwise(function(error){
							 deferred.reject(error);
						 });
					}).otherwise(function(error){
						deferred.reject(error);
					});
			   }else{
				   self.publishInner(displayMediaStream).then(function(){
				   		deferred.resolve(); 
				   }).otherwise(function(error){
				   		deferred.reject(error);
				   });
			   }
		}
		return deferred.promise;
	};
	
	
	
	publishInner = function(stream) {
		log.info("===screen.publishInner()");
		var deferred = when.defer();
		
		var self = this;
	
		if(this.status == StreamStatus.published) {
			   deferred.resolve();
		} else {
			    var track = stream.getTracks()[0];
				if(typeof track.onended !== 'undefined') {
					 track.addEventListener('ended', function () {
						log.debug("===screen track.ended,ownerId:" + self.ownerId); 
							 
						self.unpublish().then(function(){
							log.info("===screen.unpublish() success.");
							self.roomHandle.selfUser.eventEmitter.emit(UserCallback.screen_status_notify, self.status, self.id, self.name, self.roomHandle.selfUser.id);
							self.roomHandle.eventEmitter.emit(RoomCallback.screen_sharing_ended); 
						}).otherwise(function(error){
							 log.error("===screen.unpublish() error, code:"+ error.code + ", message:" + error.message);
						});
						 
					 }, false);
				} else if(typeof track.oninactive !== 'undefined') {
					  track.addEventListener('inactive', function () {
						log.debug("===screen track.inactive,ownerId:"+self.ownerId); 
						self.unpublish().then(function(){
						   log.info("===screen.unpublish() success.");
						   self.roomHandle.selfUser.eventEmitter.emit(UserCallback.screen_status_notify, self.status, self.id, self.name, self.roomHandle.selfUser.id);
						   self.roomHandle.eventEmitter.emit(RoomCallback.screen_sharing_ended);
						}).otherwise(function(error){
							 log.error("===screen.unpublish() error, code:"+ error.code + ", message:" + error.message);
						});
					  }, false);
				} else if(typeof stream.onended !== 'undefined') {
					  stream.addEventListener('ended', function (e) {
						 log.debug("===screen stream.ended,ownerId:"+self.ownerId); 
						 self.unpublish().then(function(){
							log.info("===screen.unpublish() success.");
							self.roomHandle.selfUser.eventEmitter.emit(UserCallback.screen_status_notify, self.status, self.id, self.name, self.roomHandle.selfUser.id);
							self.roomHandle.eventEmitter.emit(RoomCallback.screen_sharing_ended);
						 }).otherwise(function(error){
							 log.error("===screen.unpublish() error, code:"+ error.code + ", message:" + error.message);
						 });  
					  },false); 
				} else if(typeof stream.oninactive !== 'undefined') {
					  stream.addEventListener('inactive', function(e) {
						log.debug("===screen stream.inactive,ownerId:"+self.ownerId);
						self.unpublish().then(function(){
						   log.info("===screen.unpublish() success.");
						   self.roomHandle.selfUser.eventEmitter.emit(UserCallback.screen_status_notify, self.status, self.id, self.name, self.roomHandle.selfUser.id);
						   self.roomHandle.eventEmitter.emit(RoomCallback.screen_sharing_ended);	
						}).otherwise(function(error){
							 log.error("===screen.unpublish() error, code:"+ error.code + ", message:" + error.message);
						});  							   
					  },false);
				}
				self.publishHandleInner(self, stream,  "").then(function(){
                    deferred.resolve();
                }).otherwise(function(error){
                    deferred.reject(error);
                });
			 
		}
		return deferred.promise;
	};
	
	/**
     * @desc electron 发布桌面共享,主要用于electron v12版本之前或者该示例添加了contextIsolation: false
	 * @async
     * @param {Object} ipc renderer进程
     * @param {Array} types 共享类型,数组,例如:["window",'screen']
     * @param {Array} thumbnailSize 共享源的缩略图大小,例如: {width: 100, height: 100}
     * @param {Boolean} isShareScreenAudio 是否同时共享屏幕音频
     */
	electronPublish = function(ipc,types,thumbnailSize,isShareScreenAudio) {
		log.info("===screen.electronPublish()");
        var deferred = when.defer();
	     
        this.ipc = ipc;
        // 防止监听过多报错异常的问题
        this.ipc.setMaxListeners(50);
        if(ipc){
            this.registerElectronIPCInner(isShareScreenAudio);
        }
       
        avdEngineHandle.electronManager.getDesktopSources(types,thumbnailSize).then(function(sources){
                 deferred.resolve(sources);
         }).otherwise(function(error) {
               deferred.reject(error);
        }); 
       return deferred.promise;
	};
	
    /**
     * @desc electron 发布主屏幕桌面共享
	 * @async
     * @param {Boolean} isShareScreenAudio 是否同时共享屏幕音频
     */
	electronPrimaryDisplayPublish = function(isShareScreenAudio) {
		var deferred = when.defer();
		
	    var self = this;
		
		var primaryDisplay = avdEngineHandle.electronManager.getPrimaryDisplay();
		log.debug("===electronPrimaryDisplayPublish(),primaryDisplay:",primaryDisplay);
		var primaryDisplaySourceId = "screen:" + primaryDisplay.id;
		
		//TOOD: 在win7、win10中共享屏幕的ID,没有对应PrimaryDisplay的id,所以特殊处理写死。
		var os = require('os');
	    if(os.platform() == 'win32'){
	    	primaryDisplaySourceId = "screen:0:0";
	    }
	    
		log.debug("===electronPrimaryDisplayPublish(),primaryDisplaySourceId:",primaryDisplaySourceId);
		
		this.publishHandle(primaryDisplaySourceId, isShareScreenAudio).then(function(){
			      log.info("===screen electronPrimaryDisplayPublish(),桌面共享发布流成功,Id:"+ self.id+",name:"+self.name+",ownerId:"+self.ownerId);
	    	      deferred.resolve();
	    	}).otherwise(function(error){
	    	     deferred.reject(error);
	    });
		return deferred.promise;
    }
	
	
   registerElectronIPCInner= function(isShareScreenAudio) {
	    var self = this;
	 	this.ipc.once('selectScreenSourceId',function(event,sourceId){
            log.info('===screen registerElectronIPCInner selectScreenSourceId, sourceId: ' + sourceId)
	  	    var screen = self.roomHandle.selfUser.getScreen();
	        screen.publishHandle(sourceId, isShareScreenAudio).then(
			    function(){
					  log.info("===screen registerElectronIPCInner(),桌面共享发布流成功,Id:"+ self.id +",name:" + self.name + ",ownerId:" + self.ownerId);
				}
			).otherwise(function(error){
				
			});
	    });
		
		this.ipc.once('stopScreenSharing',function(event){
		    var screen = self.roomHandle.selfUser.getScreen();
			screen.unpublish();
		});
	}
	

   
	/**
	 * @desc桌面共享unpublish操作
	 * @async
	 */
	unpublish = function() {
		log.info("===screen.unpublish()");
		var deferred = when.defer();
		
		var self = this;
		var orderId = getRandomNum(31001, 32000);
		self.maxBandwidth = null;
		
		if(self.status == StreamStatus.published) {
			self.status = StreamStatus.init;
			self.roomHandle.masterServer.screenUnpublishHandle(self.id, self.getNewStreamByTrack(), orderId);
			
			clearTimeout(self.unpublishTimer);
			self.unpublishTimer = setTimeout(function() {
				log.debug("===screen unpublish, unpub_roomresourcemsg_rep  timeout");
                deferred.reject(new Error(ErrorConstant.operate_timeout.code, 'Cancel publishing screen sharing' + ErrorConstant.operate_timeout.message))
			}, 3000);
			
			self.roomHandle.addCallback(EngineCallback.unpub_roomresourcemsg_rep_success, function(id) {
				if(id == orderId) {
					clearTimeout(self.unpublishTimer);
					arrayUtil.objectSplice(self.roomHandle.pubScreens, self.id);
					
					
					log.info("===screen unpublish(),取消发布桌面共享成功,screenId:"+ self.id +",screenName:" + self.name + ",userId:" + self.ownerId);
					avdEngineHandle.loggerReport.info("screen unpublish(),取消发布桌面共享成功,screenId:"+ self.id +",screenName:" + self.name + ",userId:" + self.ownerId);
					
					setTimeout(function(){
                        if(self.screenAudio && self.screenAudio.status == StreamStatus.published){
                            self.screenAudio.unpublish().then(function() {
                                deferred.resolve();
                            })
                        }else{
                            deferred.resolve();
                        }

                        self.track.stop();
                        self.track = null;
                                
                        if(!self.roomHandle.isMcu()) {
                            self.stream = null;
                        }
					},50);
				}
			});
			
			self.roomHandle.addCallback(EngineCallback.unpub_roomresourcemsg_rep_error, function(error, id) {
				if(id == orderId) {
					clearTimeout(self.unpublishTimer);
					deferred.reject(error);
				}
			});
			
		}
		
		return deferred.promise;
	};

   
	/**
	 * @desc 订阅桌面共享流
	 * @async
	 */
	subscrible = function() {
		log.info("===screen subscrible(),订阅桌面共享流,screenId:"+this.id+",userId:",this.ownerId);
		avdEngineHandle.loggerReport.info("srceen subscrible(),订阅桌面共享流,screenId:"+this.id+",userId:",this.ownerId);
		
		var deferred = when.defer();
		var orderId = getRandomNum(32001, 33000);
		
		var self = this;
		self.roomHandle.masterServer.screenSubscribleHandle(self.resourceInfo,orderId);
		
		clearTimeout(self.subscribleTimer);
		self.subscribleTimer = setTimeout(function() {
			log.debug("===screen subscrible, sub_roomresourcemsg_rep_success timeout");
            deferred.reject(new Error(ErrorConstant.operate_timeout.code, 'Subscribe to screen sharing' + ErrorConstant.operate_timeout.message))
		}, 3000);
		
		self.roomHandle.addCallback(EngineCallback.sub_roomresourcemsg_rep_success, function(id) {
			if(id == orderId) {
				clearTimeout(self.subscribleTimer);
				
				setTimeout(function(){
					log.info("===screen subscrible(),订阅桌面共享流成功,screenId:"+self.id+",userId:",self.ownerId);
					deferred.resolve();
				},50);
			}
		});
		
		self.roomHandle.addCallback(EngineCallback.sub_roomresourcemsg_rep_error, function(error, id) {
			if(id == orderId) {
				clearTimeout(self.subscribleTimer);
				deferred.reject(error);
			}
		});
		
		return deferred.promise;
		
	};

    

	/**
	 * @desc 取消订阅桌面共享流
	 * @async
	 */
	unsubscrible = function() {
		log.info("===screen unsubscrible(),取消订阅桌面共享流,screenId:"+this.id+",userId:"+this.ownerId);
		avdEngineHandle.loggerReport.info("screen unsubscrible(),取消订阅桌面共享流,screenId:"+this.id+",userId:"+this.ownerId);
		
		var deferred = when.defer();
		var orderId = getRandomNum(33001, 34000);
		
		var self = this;
		self.roomHandle.masterServer.screenUnsubscribleHandle(this.resourceInfo,orderId);
		
		clearTimeout(self.unsubscribleTimer);
		self.unsubscribleTimer = setTimeout(function() {
			log.debug("===screen unsubscrible, unsub_roomresourcemsg_rep_success timeout");
            deferred.reject(new Error(ErrorConstant.operate_timeout.code, 'Unsubscribe from screen sharing' + ErrorConstant.operate_timeout.message))
		}, 3000);
		
		self.roomHandle.addCallback(EngineCallback.unsub_roomresourcemsg_rep_success, function(id) {
			if(id == orderId) {
				clearTimeout(self.unsubscribleTimer);
				
				setTimeout(function(){
					log.info("===screen unsubscrible(),取消订阅桌面共享流成功,screenId:"+self.id+",userId:"+self.ownerId);
					deferred.resolve();
				},50);
			}
		});
		
		self.roomHandle.addCallback(EngineCallback.unsub_roomresourcemsg_rep_error, function(error, id) {
			if(id == orderId) {
				clearTimeout(self.unsubscribleTimer);
				deferred.reject(error);
			}
		});
		
		return deferred.promise;
		
	};
	
	
	/**
	 * @desc 设置带宽
	 * @param {int} maxBandwidth- 最大带宽 
	 */
	setBandwidth = function(maxBandwidth) {
		var self = this;
		
		//TODO 改变带宽
		if ('RTCRtpSender' in window && 'setParameters' in window.RTCRtpSender.prototype) {
		  var sender = self.RTCRtpSender;
		  if(sender){
			 var parameters = sender.getParameters();
			 //console.log("===screen.setBandwidth(),parameters:",parameters);  
			 if (!parameters.encodings) {
			    parameters.encodings = [{}];
			 }else if(parameters.encodings == []){
			 	parameters.encodings[0] = {};
			 }
			 ////如果设置为unlimited
			 if(!maxBandwidth || maxBandwidth==0 ){
				delete parameters.encodings[0].maxBitrate; 
			 }else{
				parameters.encodings[0].maxBitrate = maxBandwidth * 1000; 
			 }
			 sender.setParameters(parameters).then(function(){
                 self.clientSetMaxBandwidth = maxBandwidth;
                 self.sendVideoStreamControl(maxBandwidth, self.resolution.width,self.resolution.height); 
                 log.info("===screen.setBandwidth(),带宽设置成功,clientSetMaxBandwidth:"+maxBandwidth);  
                   
                }).catch(function(e){
                    log.error("===screen.setBandwidth(),带宽设置失败,clientSetMaxBandwidth:"+maxBandwidth+",error:",e); 
                }); 
            }else{
                //设备打开前,设置带宽的处理。
                self.clientSetMaxBandwidth = maxBandwidth;
                self.maxBandwidth = maxBandwidth;
                log.debug("===screen.setBandwidth(),RTCRtpSender is null,clientSetMaxBandwidth:"+ maxBandwidth);       
            }
		}
	};


 
    /**
	 * @description 发PDU消息给服务器,如可以实现1080P的码流达到10M
	 * @param {Object} maxBandwidth 最大带宽
	 * @param {int} width 宽
	 * @param {int} height 高
	 * @ignore
	 */
	sendVideoStreamControl = function(maxBandwidth, width, height) {
		log.info("===Screen.sendVideoStreamControl(),maxBandwidth:"+maxBandwidth+"Kpbs, width:"+width+", height:"+height+", videoId:" + this.id + ", nodeId:" + this.roomHandle.selfUser.nodeId);
		
		var deferred = when.defer();
		
		var self = this;
		
		var orderId = getRandomNum(14001, 15000); //用于VideoStreamControlReq中的ID
		var cameraUUID = self.roomHandle.setDeviceIdByUUID(0, self.id);
		self.roomHandle.masterServer.sendVideoStreamControl(cameraUUID, maxBandwidth,width, height, orderId);
		
		clearTimeout(self.videoStreamControlTimer);
		self.videoStreamControlTimer = setTimeout(function() {
			  log.error("===Screen.sendVideoStreamControl(),带宽设置发送服务器端超时. maxBandwidth:"+maxBandwidth+"Kpbs, width:"+width+", height:"+height+", resoucceId:" + cameraUUID + ", nodeId:" + self.roomHandle.selfUser.nodeId ); 
		      deferred.reject(new Error(ErrorConstant.operate_timeout.code, 'VIDEO_STREAM_CONTROL_REQ' + ErrorConstant.operate_timeout.message))
		}, 3000)
		
		self.roomHandle.addCallback(UserCallback.video_stream_control_rep_success, function(id) {
			if(id == orderId) {
				clearTimeout(self.videoStreamControlTimer);
				log.info("===Screen.sendVideoStreamControl(), 带宽设置发送服务器端成功. maxBandwidth:"+maxBandwidth+"Kpbs,width:"+width+", height:"+height+", resoucceId:" + cameraUUID + ", nodeId:" + self.roomHandle.selfUser.nodeId ); 
				deferred.resolve();
			}
		});
		
		self.roomHandle.addCallback(UserCallback.video_stream_control_rep_error, function(error, id) {
			if(id == orderId) {
				clearTimeout(self.videoStreamControlTimer);
				log.error("===Screen.sendVideoStreamControl(),带宽设置发送服务器端失败. maxBandwidth:"+maxBandwidth+"Kpbs, width:"+width+", height:"+height+", resoucceId:" + cameraUUID + ", nodeId:" + self.roomHandle.selfUser.nodeId); 
				deferred.reject(error);
			}
		});

        return deferred.promise;
	}
	
	

	/**
	 * @description 桌面共享数据更改
	 * @param {int} level
	 * @param {String} description
	 */
	updateScreenData = function(level, description) {
		var self = this;
		log.debug("===screen.updateScreenData(),level:" + level + ",description:" + description);
		this.level = level;
		this.description = description;
		if(self.roomHandle && self.roomHandle.selfUser){
		   self.roomHandle.selfUser.reJoinScreenDescription = description;
		   self.roomHandle.masterServer.updateScreenIdMsg(self.roomHandle.selfUser.nodeId, this.id, this);
		}
	}

    /**
     * @desc electron桌面共享发布接口,electron 12之前的版本建议使用electronPublish
	 * @async
     * @param {String} sourceId - 桌面共享sourceId
     * @param {Boolean} audioEnable - 是否同时共享屏幕音频
     */
	publishHandle = function(sourceId, audioEnable) {
		log.debug("===Screen publishHandle(),sourceId :", sourceId);
		
		var deferred = when.defer();
		var self = this;
        var constraints = {
			audio: {
                mandatory: {
					chromeMediaSource: "desktop",
                    googEchoCancellation: avdEngineHandle.enableEchoCancellation,
                    googNoiseSuppression: avdEngineHandle.enableNoiseSuppression,
                    googAutoGainControl: avdEngineHandle.enableAutoGainControl,
                    echoCancellation: avdEngineHandle.enableEchoCancellation
                }
            },
			video: {
				mandatory: {
                    chromeMediaSource: "desktop",
                    chromeMediaSourceId: sourceId,
                    maxWidth: self.resolution.width,
                    maxHeight: self.resolution.height,
                    minFrameRate: self.frameRate,
                    maxFrameRate: self.frameRate
                }
            }
        }
        if(!audioEnable){
            delete constraints.audio;
        }
        log.debug("===Screen publishHandle constraints: ", JSON.stringify(constraints));
		// navigator.webkitGetUserMedia(constraints, function(stream) {
        navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
            log.debug("===Screen publishHandle() webkitGetUserMedia success, gotShareStream.stream: ", stream);

			//TODO 测试看会不会有回调
			if(stream && stream.getTracks()) {
				var track = stream.getVideoTracks()[0];
                if(audioEnable){
                    var tempAudioTrack = stream.getAudioTracks()[0];
                    if(tempAudioTrack){
                        if(self.screenAudio){
                            self.screenAudio.track = tempAudioTrack;
                            self.screenAudio.publish();
                        }
                    }
                }
				if(typeof track.onended !== 'undefined') {
					track.onended = function() {
						log.debug("screen.publish(),track.onended");

						if(self.track) {
							self.unpublish();
							self.roomHandle.selfUser.eventEmitter.emit(UserCallback.screen_status_notify, self.status, self.id, self.name, self.roomHandle.selfUser.id);
						}
						self.roomHandle.eventEmitter.emit(RoomCallback.screen_sharing_ended);
					}
				} else {
					//chrome54开始不支持该方法 stream.onended
					if(typeof stream.onended !== 'undefined') {
						stream.onended = function() {
							log.debug("===screen.publish(),stream.onended");

							if(self.track) {
								self.unpublish();
								self.roomHandle.selfUser.eventEmitter.emit(UserCallback.screen_status_notify, self.status, self.id, self.name, self.roomHandle.selfUser.id);
							}
							self.roomHandle.eventEmitter.emit(RoomCallback.screen_sharing_ended);
						};
					} else {
						stream.oninactive = function() {
							log.debug("===screen.publish(),stream.oninactive");

							if(self.track) {
								self.unpublish();
								self.roomHandle.selfUser.eventEmitter.emit(UserCallback.screen_status_notify, self.status, self.id, self.name, self.roomHandle.selfUser.id);
							}
							self.roomHandle.eventEmitter.emit(RoomCallback.screen_sharing_ended);
						}
					}
				}
			}
			
			self.publishHandleInner(self,stream,sourceId,deferred).then(function(streamId){
                deferred.resolve(streamId)
            }).otherwise(function(err){
                deferred.reject(err);
            });

		}).catch(function(error) {
			log.debug('An error occurred: ' + JSON.stringify(error));
			// var error = new Error(ErrorConstant.screen_sharing_plugin_not_accessible);
			deferred.reject(error);
            if(self.ipc){
                self.ipc.emit('screen-published-error', error);
            }
		});
		return deferred.promise;
	};
	
	

	publishHandleInner = function(self,stream,streamId){
		    var self = this;
            var deferred = when.defer();
		    var orderId = getRandomNum(30000, 31000); //用于PubRoomResourceMsgRep中的ID
			
			var bit = self.roomHandle.calInitVideoBitrate(self.resolution.width,self.resolution.height);
			self.maxBandwidth = bit.maxBit;
			
           //console.log("===ds000000000000");
			self.track = stream.getVideoTracks()[0];
			
			if(self.roomHandle.selfUser.screenStream == null) {
				//console.log("===ds2222222222222222222222");
				self.roomHandle.selfUser.screenStream = stream;
			} else {
				//console.log("===ds333333333333333");
				self.roomHandle.selfUser.screenStream.addTrack(self.track);
			}
			
			var screenStream = self.getNewStreamByTrack();
			self.roomHandle.masterServer.screenPublishHandle(self.id, screenStream, orderId);
			
			clearTimeout(self.openTimer);
			self.openTimer = setTimeout(function() {
                log.debug("===screen publish,pub_roomresourcemsg_rep_success  timeout");
                deferred.reject(new Error(ErrorConstant.operate_timeout.code, 'Publishing screen sharing' + ErrorConstant.operate_timeout.message))
			    if(self.track){
					self.track.stop();
					self.track = null;
				}
			}, 3000)
			
			self.roomHandle.addCallback(EngineCallback.pub_roomresourcemsg_rep_success, function(id) {
				//console.log("===ds000000000000111111");
				if(id == orderId) {
					clearTimeout(self.openTimer);
					self.status = StreamStatus.published;
					
					//console.log("===ds1111111111111111");
					self.roomHandle.pubScreens.push(self);
                    log.info("===screen publishHandleInner(),桌面共享视频发布流成功,Id:"+ self.id+",name:"+self.name+",ownerId:"+self.ownerId);
                    if(self.ipc){
                        self.ipc.emit('screen-published');
                    }
					self.roomHandle.selfUser.eventEmitter.emit(UserCallback.screen_status_notify, self.status, self.id, self.name, self.roomHandle.selfUser.id);
					deferred.resolve(streamId);
				}
			});

			self.roomHandle.addCallback(EngineCallback.pub_roomresourcemsg_rep_error, function(error, id) {
				if(id == orderId) {
					clearTimeout(self.openTimer);
					if(self.track){
						self.track.stop();
						self.track = null;
					}
					log.info("===screen publishHandleInner(),桌面共享视频发布流失败,Id:"+ self.id+",name:"+self.name+",ownerId:"+self.ownerId+", error:",JSON.stringify(error));
                    if(self.ipc){
                        self.ipc.emit('screen-published-error', error);
                    }
				    deferred.reject(error);
				}
			});
        return deferred.promise;
	}
	
	
	/**
	* @desc 桌面共享流渲染进视频控件
	* @param {Object} element - 视频控件对象 
	* @param {Object} stream - 桌面共享流
	*/
	attachScreenElementMediaStream = function(element,stream){
		if(stream !=null){
			this.element = element;
		}
		if(element){
			element.srcObject = stream;
		}
	};

    /**
     * @desc 屏幕共享时是否同时共享屏幕音频
     * @param {Boolean} enabled 
     */
   setScreenAudioEnabled = function(enabled) {
        this.screenAudioEnabled = enabled;
    }


    /**
     * @desc 屏幕共享静音
     */
    muteScreenAudio = function() {
        if(this.screenAudio){
            this.screenAudio.muteScreenAudio();
        }
    }

    /**
     * @desc 取消屏幕共享静音
     */
    unmuteScreenAudio = function() {
        if(this.screenAudio){
            this.screenAudio.unmuteScreenAudio();
        }
    }
}
	return Screen;
});