# 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;
    });