# stream/audio.js

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

    	/**
    	 * @desc 音频Audio构造函数。
    	 * @constructor
    	 * @alias Audio
    	 * @param {String} id - 设备Id
    	 * @param {String} name - 设备名称
    	 */
    	class Audio extends Base {

    	  constructor(id, name, roomHandle) {
    	 	super(id, name);

    		this.roomHandle = roomHandle;

    		this.audioLevel = 0;  //语音激励

    		this.isPubState = false; //防止重复发布，在发布过程中该状态为true

    		this.isMonitorAudioLevel = false;

    		this.monitorAudioLevelIntervalId = null;

    		this.openTimer = null;

    		this.closeTimer = null;

    		this.subscribleTimer =  null;

    		this.unsubscribleTimer = null;
    	 };

    	/**
    	 * @desc 打开音频及把流渲染进视频控件,同时进行publish操作。
    	 * @async
    	 * @param {Object} element - 音频控件对象
    	 */
    	openMicrophone = function(element) {
    		log.info("===audio.openMicrophone()");
    		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("===audio.openMicrophone() 发布视频流异常, room state: " + self.roomHandle.roomJoinState);
                deferred.reject(err);
                return;
            }
    		// var error = doFsCheck(FTConstant.audio, Error)
    		// if(error) {
    		// 	deferred.reject(error);
    		// 	return deferred.promise;
    		// }

    		var orderId = getRandomNum(20000, 21000); //用于PubRoomResourceMsgRep中的ID

    		if(self.track) {
    			var microphoneUUID = self.roomHandle.setDeviceIdByUUID(2, self.id);
    			var audioStream = self.getNewStreamByTrack();

    			if(self.isPubState){
    				if(self.status == StreamStatus.published){
    					log.debug("===audio openMicrophone(self.track!=null),isPubState =true && self.status == StreamStatus.published to return");
    					deferred.resolve();
    					return deferred.promise;
    				}else if(self.status == StreamStatus.muted){
    					log.debug("===audio openMicrophone(self.track!=null),isPubState =true && self.status == StreamStatus.muted to audio.unmuteMicrophone()");
    					self.unmuteMicrophone();
    					deferred.resolve();
    					return deferred.promise;
    				}
    			}

    			if(self.isPubState){
    				log.debug("===audio openMicrophone(self.track!=null),isPubState =true  to return");
    				deferred.resolve();
    				return deferred.promise;
    			}

    			self.isPubState = true;
    			self.roomHandle.masterServer.audioPublishHandle(microphoneUUID, audioStream, orderId);

    			clearTimeout(self.openTimer);
    			self.openTimer = setTimeout(function() {
    				self.isPubState = false;
    				log.debug("===audio openMicrophone(self.track!=null),pub_roomresourcemsg_rep timeout");
                    deferred.reject(new Error(ErrorConstant.operate_timeout.code, 'Release audio' + ErrorConstant.operate_timeout.message))
    			}, 3000)

    			self.roomHandle.addCallback(EngineCallback.pub_roomresourcemsg_rep_success, function(id) {
    				if(id == orderId) {
    					clearTimeout(self.openTimer);

    					self.state = StreamStatus.opened;

    					if(typeof(element) != 'undefined' && element && element != '') {
    						self.element = element;
    						element.srcObject = audioStream;
    					}
    					self.status = StreamStatus.published;
    					if(!self.roomHandle.hasObject(self.roomHandle.pubAudios,self)){
    						self.roomHandle.pubAudios.push(self);
    					}

    					log.info("===audio openMicrophone(),打开音频及发布流成功,callback microphone_status_notify  (self.track!=null),status:"+self.status+",audioId:"+ self.id+",userId:"+self.ownerId);
    					avdEngineHandle.loggerReport.info("audio openMicrophone(),打开音频及发布流成功,(self.track!=null),audioId:"+ self.id+",userId:"+self.ownerId);
    					self.roomHandle.selfUser.eventEmitter.emit(UserCallback.microphone_status_notify, self.status, self.id, self.name, self.roomHandle.selfUser.id);

    					deferred.resolve();
    				}
    			});

    			self.roomHandle.addCallback(EngineCallback.pub_roomresourcemsg_rep_error, function(error, id) {
    				if(id == orderId) {
    					clearTimeout(self.openTimer);

    					self.isPubState = false;
    					log.error("===audio openMicrophone(),打开音频及发布流失败,(self.track!=null),audioId:"+ self.id+",userId:"+self.ownerId+",error:"+JSON.stringify(error));
    					avdEngineHandle.loggerReport.error("audio openMicrophone(),Failed to open audio and publish stream,(self.track!=null),audioId:"+ self.id+",userId:"+self.ownerId+",error:"+JSON.stringify(error));
    					deferred.reject(error);
    				}
    			});

    		} else  {
    			obtainUserMedia(self, null).then(function(stream) {
    					self.track = stream.audioStream.getAudioTracks()[0];

    					if(self.roomHandle.selfUser.stream ==null){
    						 self.roomHandle.selfUser.stream = stream.audioStream;
    					}else{
    						 self.roomHandle.selfUser.stream.addTrack(self.track);
    					}

    					self.state = StreamStatus.opened;

    					var microphoneUUID = self.roomHandle.setDeviceIdByUUID(2, self.id);
    					var audioStream = self.getNewStreamByTrack();

    					if(self.isPubState){
    						log.debug("===audio openMicrophone(self.track=null),isPubState =true  to return");
    						deferred.resolve();
    						return deferred.promise;
    					}

    					self.isPubState = true;
    					self.roomHandle.masterServer.audioPublishHandle(microphoneUUID, audioStream, orderId);

                        clearTimeout(self.openTimer);
    					self.openTimer = setTimeout(function() {
    						self.isPubState = false;
    						log.debug("===audio openMicrophone(self.track==null),pub_roomresourcemsg_rep timeout");
                            deferred.reject(new Error(ErrorConstant.operate_timeout.code, 'Release audio ' + ErrorConstant.operate_timeout.message))
    					}, 3000)

    					self.roomHandle.addCallback(EngineCallback.pub_roomresourcemsg_rep_success, function(id) {
    						if(id == orderId) {
    							clearTimeout(self.openTimer);

    							if(typeof(element) != 'undefined' && element && element != '') {
    								self.element = element;
    								element.srcObject = audioStream;
    							}

    							self.status = StreamStatus.published;

    							if(!self.roomHandle.hasObject(self.roomHandle.pubAudios,self)){
    								self.roomHandle.pubAudios.push(self);
    							}

    							log.info("===audio openMicrophone(),打开音频及发布流成功,callback microphone_status_notify (self.track==null),status:"+self.status+",audioId:"+ self.id+",userId:"+self.ownerId);
    							avdEngineHandle.loggerReport.info("audio openMicrophone(),打开音频及发布流成功,(self.track==null),audioId:"+ self.id+",userId:"+self.ownerId);
    							self.roomHandle.selfUser.eventEmitter.emit(UserCallback.microphone_status_notify, self.status, self.id, self.name, self.roomHandle.selfUser.id);
    							deferred.resolve();
    						}
    					});

    					self.roomHandle.addCallback(EngineCallback.pub_roomresourcemsg_rep_error, function(error, id) {
    						if(id == orderId) {
    							clearTimeout(self.openTimer);

    							self.isPubState = false;
    							log.error("===audio openMicrophone(),打开音频及发布流失败,(self.track==null),audioId:"+ self.id+",userId:"+self.ownerId+",error:"+JSON.stringify(error));
    							avdEngineHandle.loggerReport.error("audio openMicrophone(),Failed to open audio and publish stream,(self.track==null),audioId:"+ self.id+",userId:"+self.ownerId+",error:"+JSON.stringify(error));
    					        deferred.reject(error);
    						}
    					});

    				}).otherwise(function(e) {
    					deferred.reject(e);
    				});
    		}

    		return deferred.promise;
    	};

    	/**
    	 * @desc 关闭音频,同时进行unpublish操作。
    	 * @async
    	 */
    	closeMicrophone = function() {
    		log.info("===audio.closeMicrophone()");

    		var deferred = when.defer();

    		var self = this;
    		var orderId = getRandomNum(21001, 22000);

    		if(self.status == StreamStatus.published || self.status == StreamStatus.muted) {
    			self.isPubState = false;

    			arrayUtil.objectSplice(self.roomHandle.pubAudios, this.id);

    			self.status = StreamStatus.init;
    			self.roomHandle.selfUser.eventEmitter.emit(UserCallback.microphone_status_notify, self.status, self.id, self.name, self.roomHandle.selfUser.id);

    			var microphoneUUID = self.roomHandle.setDeviceIdByUUID(2, self.id);
                var audioStream = self.getNewStreamByTrack();
    			self.roomHandle.masterServer.audioUnpublishHandle(microphoneUUID, audioStream, orderId);

    			clearTimeout(self.closeTimer);
    			self.closeTimer = setTimeout(function() {
    				self.isPubState = false;
    				log.debug("===audio closeMicrophone,unpub_roomresourcemsg_rep timeout");
                    deferred.reject(new Error(ErrorConstant.operate_timeout.code, 'Unpublish audio' + ErrorConstant.operate_timeout.message))
    			}, 3000);

    			self.roomHandle.addCallback(EngineCallback.unpub_roomresourcemsg_rep_success, function(id) {
    				if(id == orderId) {
    					clearTimeout(self.closeTimer);

    					//第三方导入流closeMicrophone时，不对本地track清场，在user.deleteCustomAudioTrack()时统一清场。
    					if(self.id.indexOf('custom_audio') !== -1 ){
    						self.setAudioLevel(0);
    						var stream = self.roomHandle.selfUser.stream;
    						if(stream){
    							stream.getTracks().forEach(function(track) {
    								if(self.track && self.track.id == track.id){
    									track.stop();
    								}
    							});
    						}

    						if(self.element) {
    							var elementStream = self.element.srcObject;
    							if(elementStream){
    								elementStream.getTracks().forEach(function(track) {
    									 track.stop();
    								});
    							}

    							self.element.srcObject = null;
    							self.element = null;
    						}

    						self.track.stop();
    						self.track = null;
    					}

    					log.info("===audio closeMicrophone(),关闭音频及取消发布流. audioId:"+ self.id+",userId:"+self.ownerId);
    					avdEngineHandle.loggerReport.info("audio closeMicrophone(),关闭音频及取消发布流操作. audioId:"+ self.id+",userId:"+self.ownerId);

    					setTimeout(function(){
    						deferred.resolve();
    					},50);
    				}
    			});

    			self.roomHandle.addCallback(EngineCallback.unpub_roomresourcemsg_rep_error, function(error, id) {
    				if(id == orderId) {
    					clearTimeout(self.closeTimer);

    					self.isPubState = false;
    					log.error("===audio closeMicrophone(),关闭音频及发布流失败. audioId:"+ self.id+",userId:"+self.ownerId+",error:"+JSON.stringify(error));
    					avdEngineHandle.loggerReport.error("audio closeMicrophone(),Failed to close the audio and publish stream. audioId:"+ self.id+",userId:"+self.ownerId+",error:"+JSON.stringify(error));
    					deferred.reject(error);
    				}
    			});
    		}

    		return deferred.promise;
    	};

    	/**
    	 * @desc 订阅音频流
    	 * @async
    	 */
    	subscrible = function() {
    		  log.info("===audio subscrible(),订阅音频流操作, audioId:"+ this.id+",userId:"+this.ownerId);
    		  avdEngineHandle.loggerReport.info("audio subscrible(),订阅音频流操作, audioId:"+ this.id+",userId:"+this.ownerId);

    		  var deferred = when.defer();

    		  var orderId = getRandomNum(22001, 23000);

    		  var self = this;
    		  self.roomHandle.masterServer.audioSubscribleHandle(self.resourceInfo,orderId);

    		  clearTimeout(self.subscribleTimer);
    		  self.subscribleTimer = setTimeout(function() {
    		  	log.debug("===audio subscrible, sub_roomresourcemsg_rep_success timeout");
                  deferred.reject(new Error(ErrorConstant.operate_timeout.code, 'Subscribe to audio' + 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("===audio subscrible(),订阅音频流成功,audioId:"+ 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("===audio unsubscrible(),取消订阅音频流操作，audioId:"+ this.id+",userId:"+this.ownerId);
    		avdEngineHandle.loggerReport.info("audio unsubscrible(),取消订阅音频流操作，audioId:"+ this.id+",userId:"+this.ownerId);

    		var deferred = when.defer();
    		var orderId = getRandomNum(23001, 24000);

    		var self = this;

    		//console.log("===audio unsubscrible(),this.resourceInfo.stream.stream_name:"+this.resourceInfo.stream.stream_name);
    		self.roomHandle.masterServer.audioUnsubscribleHandle(this.resourceInfo,orderId);

    		clearTimeout(self.unsubscribleTimer);
    		self.unsubscribleTimer = setTimeout(function() {
    			log.debug("===audio unsubscrible, unsub_roomresourcemsg_rep_success timeout");
                deferred.reject(new Error(ErrorConstant.operate_timeout.code, 'Unsubscribe Audio' + 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("===audio unsubscrible(),取消订阅音频流成功,audioId:"+ 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 禁音
    	 */
    	muteMicrophone = function() {
    		log.info("===audio.muteMicrophone()");
    		var self = this;
    		if(this.status == StreamStatus.published) {
    			this.status = StreamStatus.muted;
    			self.roomHandle.selfUser.eventEmitter.emit(UserCallback.microphone_status_notify, this.status, this.id, this.name, self.roomHandle.selfUser.id);

                var stream = self.roomHandle.selfUser.stream;
    			stream.getTracks().forEach(function(track) {
    				if(track.id ==  self.track.id){
    				  	track.enabled = false;
    				}
    			});

    			if(self.element) {
    				var elementStream = self.element.srcObject;
    				if(elementStream){
    					elementStream.getTracks().forEach(function(track) {
    						if(track.id ==  self.track.id){
    						   track.enabled = false;
    						}
    					});
    				}
    			}

                if(self.track){
                	self.track.enabled = false;
                }

    			var senders = self.roomHandle.traceablePeerConnection.getToMCUPeerConnection().getSenders();
    			//console.log("AAAAAAA00000000,senders:",senders);
    			if(senders){
    				for (var i = 0; i < senders.length; i++) {
                        var sender = senders[i];
                        //console.log("AAAAAAA1111111111111,sender:",sender);
                        if(sender && sender.track && sender.track.kind == "audio" && sender.track.id == self.track.id){
                            // console.log("AAAAAAA2222222222,sender.track.enabled:",sender.track.enabled);
                            sender.track.enabled = false;
                        }
    				}
    			}

    			var microphoneUUID = self.roomHandle.setDeviceIdByUUID(2, this.id);
    			self.roomHandle.masterServer.updateSpeakerMsg(self.roomHandle.selfUser.nodeId, microphoneUUID, this);

    			log.info("===audio muteMicrophone(),禁音. Id:"+ self.id+",ownerId:"+self.ownerId+",status:"+self.status);
    			avdEngineHandle.loggerReport.info("audio muteMicrophone(),禁音. Id:"+ self.id+",ownerId:"+self.ownerId+",status:"+self.status);
    		}
    	};

    	/**
    	 * @desc 取消禁音
    	 */
    	unmuteMicrophone = function() {
    		log.info("===audio.unmuteMicrophone()");
    		var self = this;
    		if(this.status == StreamStatus.muted) {
    			this.status = StreamStatus.published;
    			self.roomHandle.selfUser.eventEmitter.emit(UserCallback.microphone_status_notify, this.status, this.id, this.name, self.roomHandle.selfUser.id);

                var stream = self.roomHandle.selfUser.stream;
    			stream.getTracks().forEach(function(track) {
    				  if(track.id ==  self.track.id){
    				  	   track.enabled = true;
    				  }
    			});

    			if(self.element) {
    				var elementStream = self.element.srcObject;
    				if(elementStream){
    					elementStream.getTracks().forEach(function(track) {
    						 if(track.id ==  self.track.id){
    							track.enabled = true;
    						 }
    					});
    				}
    			}

                if(self.track){
                	self.track.enabled = true;
                }

    			var senders = self.roomHandle.traceablePeerConnection.getToMCUPeerConnection().getSenders();
    			if(senders){
    				for (var i = 0; i < senders.length; i++) {
    					 var sender = senders[i];
    					 if(sender && sender.track && sender.track.kind == "audio" && sender.track.id == self.track.id){
                            sender.track.enabled = true;
    					 }
    				}
    			}

    			var microphoneUUID = self.roomHandle.setDeviceIdByUUID(2, this.id);
    			self.roomHandle.masterServer.updateSpeakerMsg(self.roomHandle.selfUser.nodeId, microphoneUUID, this);

    			log.info("===audio unmuteMicrophone(),取消禁音. Id:"+ self.id+",ownerId:"+self.ownerId+",status:"+self.status);
    			avdEngineHandle.loggerReport.info("audio unmuteMicrophone(),取消禁音. Id:"+ self.id+",ownerId:"+self.ownerId+",status:"+self.status);
    		}
    	};

    	/**
    	 * @desc 获取禁音状态
    	 */
    	ismuteMicrophone = function() {
    		var ismute = false;
    		if(this.status == StreamStatus.muted) {
    			ismute = true;
    		}
    		return ismute;
    	};

    	/**
    	 * @desc 设置语音激励级别
    	 * @param {int} audioLevel -语音激励级别
    	 */
    	setAudioLevel = function(audioLevel) {
    		this.audioLevel = audioLevel;
    	};

    	/**
    	 * @desc 获取语音激励级别
    	 */
    	getAudioLevel = function() {
    		return this.audioLevel;
    	};

      }
    	return Audio;
    });