
/**
 * video工具类
 * @author savage
 * @version 1.0.2
 * @update 2017-02-10 13:53:46
 */

(function (root, factory) {
if (typeof define === 'function' && define.amd) {
    // AMD
    define(['jquery'], factory);
} else if (typeof exports === 'object') {
    // Node, CommonJS之类的
    module.exports = factory(require('jquery'));
} else {
    // 浏览器全局变量(root 即 window)
    root.scooper = root.scooper || {};

    root.scooper.video = factory(root.jQuery);
}
}(this, function ($) {
	"use strict";
		
	window.console = window.console || (function(){ 
		var c = {}; c.log = c.warn = c.debug = c.info = c.error = c.time = c.dir = c.profile 
		= c.clear = c.exception = c.trace = c.assert = function(){}; 
		return c; 
	})();
	
	/**
	 * 立即执行函数形式
	 * 兼容IE8 indexOf
	 */
	(function () {
	    if(Array.prototype.indexOf) {
	        return;
	    }
	    Array.prototype.indexOf = function(item) {
	        var len = this.length >>> 0; //保证结构为非负数
	        
	        for(var i = 0; i<len ; i++) {
	            if(i in this && this[i] === item) {
	                return i;
	            }
	        }
	        return -1;
	    }
	})();
	
	/**
	 * 闭包
	 * 为事件添加唯一标识字符串
	 */
	var guid = (function() {
	    var id = 1;
	    return function() {
	        return 'SCVIDEO_ID_'+ (++id).toString();
	    }
	})();
	
    /**
     * 公共方法
     * 判断是否为IE
     */
    function isIE() {
        return !!window.ActiveXObject || "ActiveXObject" in window;
    }
    
	/**
	 * 克隆对象
	 * 让新出来的对象是独立的
	 */
	function cloneObj(obj) {
		var str, newObj = $.isArray(obj)?[]:{};
		if ( typeof obj != 'object' ) {
			return;
		}
		
		if (window.JSON) {
			str = JSON.stringify(obj);
			newObj = JSON.parse(str);
		} else {
			$.each(obj,function(key,val) {
				newObj[key] = typeof val == 'object' ? cloneObj(val) : val;
			});
		}
		return newObj;
	}
	
	/**
	 * 公共方法
	 * 提示
	 */
	function promptSuccess(msg, type) {
		console.log(msg);
		//panduanpromptView弹层对象是否引入
		"undefined" != typeof(promptView) && promptView.showSuccess(msg);
	}	
	function promptFailed(msg, type) {
		console.error(msg);
		"undefined" != typeof(promptView) && promptView.showFailed(msg);
	}	
	function promptAlarm(msg, type) {
		console.info(msg);
		"undefined" != typeof(promptView) && promptView.showAlarm(msg);
	}
	
	/**
	 * 公共方法
	 * 判断是否是安全连接
	 */
	function checkIsHttp() {
		var protocolStr = document.location.protocol;
		if(protocolStr == "http:" /*&& window.location.hostname != "localhost"*/ ) return true;
		return false;
	}
	
	/**
	 * 事件对象包装类，通过事件type，加载必要的属性
	 *  @class
	 */
	function VideoEvent(type,target) {
	    this.type = type;
	    this.returnValue = true;
	    this.target = target || null;
	    this.currentTarget = null;
	}
    
	/**
	 * 轮巡工具类
	 */
	var PollTimer = /** @class */ (function () {
	    function PollTimer(cb, time) {
	        cb(true); // 首次执行
	        this.timerId = setInterval(cb, time * 1000);
	    }
	    PollTimer.prototype.stop = function () {
	        if (!this.timerId)
	            return;
	        clearInterval(this.timerId);
	        this.timerId = 0;
	    };
	    return PollTimer;
	}());
	
	//事件
	function Listener() {
	    // 在构造函数中进行初始化
	    this._listeners = {};
	}
	
	Listener.prototype = {

        constructor: Listener,
        /**
		 * 添加事件
		 */
		addListener: function(type,handler,key){
		    if (typeof handler != 'function') {
	            return;
		    }
		    var t = this._listeners,id;
		    if (typeof key == "string" && key) {
	            if (/[^\w\-]/.test(key)) {
	                throw("nonstandard key:" + key);
	            } else {
	                handler.hashCode = key; 
	                id = key;
	            }
	        }
	        type.indexOf("on") != 0 && (type = "on" + type);
	        typeof t[type] != "object" && (t[type] = {});
	        id = id || guid();
	        handler.hashCode = id;
	        t[type][id] = handler;
		},
		
		/**
		 * 删除事件
		 */
		removeListener: function(type,handler){
		    type.indexOf("on") != 0 && (type = "on" + type);
		    var t = this._listeners;
		    if (!t[type]) {
		        return;
		    }
		    if (handler) {
		        if (typeof handler == 'function') {
		            handler = handler.hashCode;
		        }else if (typeof key != "string"){
		            return;
		        }
		        t[type][handler] && delete t[type][handler];
		    }else{
		        t[type] = {};
		    }
		},
		/**
		 * 派发事件
		 */
		dispatch: function(e,options){
		    if (typeof e == 'string') {
		        e = new VideoEvent(e);
		    }
		    options = options || {};
		    for (var i in options) {
		        e[i] = options[i];
		    }
		    var i, t = this._listeners, p = e.type;
		    e.target || (e.target = this);
		    e.currentTarget = this;
		    p.indexOf("on") != 0 && (p = "on" + p);
		    typeof this[p] == 'function' && this[p].apply(this, arguments);
		    if (typeof t[p] == "object") {
		        for (i in t[p]) {
		            t[p][i].call(this, e);
		        }
		    }
		    return e.returnValue;
		}
	}
	
	var videoListener = new Listener();
	
	/**
	 * 使用ocx方式的video工具类
	 * @author savage
	 * @version 1.0.0
	 */
    function VideoOcx($dom, opts){
        if (!isIE()) {
            console.log('视频控件不支持非IE浏览器');
            return this._getTipObj();
        }
        if (!opts) {
            console.error('VideoOcx的参数opts不能为空');
            return;
        }
        this._init($dom,opts);
    }
    
    /**
     * 使用ocx方式的视频播放的方法
     */
    VideoOcx.prototype = {

        constructor: VideoOcx,
        /**
         * 播放视频
         * 参数：index(视频窗口编号，从0开始) video(视频设备id，即devId) id(标识，空的话使用设备id) opts(其他参数)
         * 返回true/false
         */
        play: function(index, video, id, opts){
            /*if (!$.isNumeric(video*1)) {
                throw new Error('video is not number,id = '+id);
            }*/
            console.log("play >>> " + "video=" + video + "; id=" + id + "; index=" + index);
            this.dispatch('beforeplay',{index:index, video:video, id:id});
            
            this._obj.SCWebSetCurrentWindow(index);
            var playId = this._obj.SCWebRealPlay(video, this._opts.streamType);
            console.log("play = " + playId);
            
            opts = opts || {};
            playId > 0 && (this.videoStatus[index] = {
                video: video,
                id: id,
                playId: playId,
                opts:opts
            },this.dispatch('playsuccess', this.videoStatus[index]));
            
            if (playId < 0) {
            	var name = opts.name || '视频';
            	promptFailed(name + '播放失败！');
            }
            
            return playId > 0;
        },
        
        /**
         * 在序号最小的空闲窗口播放视频
         * 参数：index(视频窗口编号，从0开始) video(视频设备id，即devId) opts(其他参数)
         * 返回true/false
         */
        playByOrder: function(video, id, opts){
            var freeWindow = this._getMinIndexFreeWindow(0);
            
            if(freeWindow == -1){
			    return this.playInChoice(video,id,opts);
		    }
		    return this.play(freeWindow,video,id,opts);
        },
        
        /**
         * 扩展视频窗口数的播放方式
         */
        playByOrderExpandWindow: function(video,id,opts){
        	
        	var freeWindow = this._getMinIndexFreeWindow(0);
        	
        	while (this._opts.windows < 16 && freeWindow == -1) {
        		var zoom = Math.sqrt(this._opts.windows*1)+1;
        		
        		if (this._opts.windows == 6) {
        			this.setWindowsNum(9);
        		} else {
        			this.setWindowsNum(Math.pow(zoom,2));
        		}     		

        		freeWindow = this._getMinIndexFreeWindow(zoom-1);
        	}
  
        	if(freeWindow == -1 || 
        			(this._getChoiceWindow() != -1 && !this.getInChoiceVideo())){
			    return this.playInChoice(video,id,opts);
		    }
		    return this.play(freeWindow,video,id,opts);
        },
        
        /**
         * 播放所有视频
         */
        playAll: function(array){
            if (array.length > this._opts.windows) {
                throw new Error('windows is not enough');
            }
            var me = this;
            me.closeAll();
            $.each(array,function(i,obj){
                me.play(i,obj.video,obj.id,obj.opts);
            });
        },
        /**
         * 在鼠标选中的窗口中播放视频
         */
        playInChoice: function(video,id,opts){
            var index = this._obj.SCWebGetCurrentWindowIndex();
            this.videoStatus[index] && this.close(index);
            return this.play(index,video,id,opts);
        },
        /**
         * 如果被指定的窗口有视频id，则播放
         */
        playMulWindows: function(indexs) {
            var me = this;
            $.each(indexs,function(i,index){
                me.videoStatus[index] && me.play(index,me.videoStatus[index].video,me.videoStatus[index].id);
            });
        },
        /** 
         * 检索当前点的视频是否被播放，被播放则返回播放的视频窗口
         */
        isPlaying: function(id){
            var index = -1;
    	    $.each(this.videoStatus,function(key,val){
                if (id == val.id) {
                    index = key;
                    return false;
                }
    	    });
    	    return index;
        },
        
        /**
         * 关闭语音
         * @param window
         */
        closeVoice : function(window) {
        	
        	 this._obj.CWebVoiceComControl(window,0);
        },
        
        getWindowByPlayId: function(playId) {
        	var index = -1;
    	    $.each(this.videoStatus,function(key,val){
                if (playId == val.playId) {
                    index = key;
                    return false;
                }
    	    });
    	    return index;
        },
        
        getPlayIdBywindow : function(index) {
        	return this.videoStatus[index].playId;
        },
        
        /**
         * 关闭指定窗口的视频
         */
        close: function(index,isSave){
        	
            if (!this.videoStatus[index] || index >= this._opts.windows || this._disableClosed.indexOf(index*1) > -1 ) {
                return;
            }
            this._obj.SCWebSetCurrentWindow(index);
		    var close = this._obj.SCWebStopRealPlay(this.videoStatus[index].playId);
		    console.log("close = "+close);
   
            if (!isSave) {
                this.dispatch('afterclose',this.videoStatus[index]); 
                delete this.videoStatus[index];
            }

        },
        
        /**
         * 
         */
        closeHistory: function(playId) {
        	var close = this._obj.SCWebStopRealPlay(playId);
        	console.log("close = "+close);
        },
        
        /**
         * 关闭所有视频
         * TODO 不可关闭
         */
        closeAll: function(isSave){
            var me = this;
            isSave || (this._disableClosed = []);
            var windows = me._obj.SCWebGetRealPlayWindows();
            if (windows) {
                $.each(windows.split(','),function(i,index){
                    me.close(index,isSave);
                });
            }
        },
        
        /**
         * 获取视频窗口
         * @returns
         */
        getWindowsPlay : function() {
        	var me = this;
            var windows = me._obj.SCWebGetRealPlayWindows();
            return windows;
        },
        
        /**
         * 设置鼠标选中窗口
         */
        setChoiceWindow: function(index) {
            this._obj.SCWebSetCurrentWindow(index);
        },
        /**
         * 获取视频窗口数
         */
        getWindowsNum: function() {
            return this._opts.windows;
        },
        /**
         * 是否还有空闲窗口
         */
        hasFreeWindow: function() {
        	return this._obj.SCWebGetFreeWindows() != '';
        },
        
        /**
         * 设置视频窗口数
         */
        setWindowsNum: function(num,extra) {
        	var me = this;
        	num = num*1;
        	var result;
        	if (extra) {
        		result = me._obj.SCWebDecoderSetExtraScreenMode(num);
        	} else {
        		result = me._obj.SCWebDecoderSetScreenMode(num);
        	}
        	console.log("setWindowsNum >>> " + "result=" + result);
            /*extra
            ? me._obj.SCWebDecoderSetExtraScreenMode(num)
            : me._obj.SCWebDecoderSetScreenMode(num);*/
        	num = num == 66 ? 6 : num;
        	me._changeWindowsAction(num);
            me.dispatch('screenchange',{windowNums: num});
            me._opts.windows = num;
            me._opts.extra = extra;

        },
        
        /**
         * 询问是否无可用窗口
         */
        isUnavailable: function() {
        	return this._opts.windows == 16 && !this.hasFreeWindow();
        },
        
        disableClosed: function(num){
        	$.isNumeric(num) ? this._disableClosed.push(num) : 
        		$.isArray(num) && (this._disableClosed = this._disableClosed.concat(num));
        	
        },
        
        enableClosed: function(){
        	this._disableClosed = [];
        },
        
        //轮巡就是建立一个轮巡数组，然后根据最大屏幕数去遍历数组，记录当前轮巡下标，并标记该视频已被打开，如果视频关闭后 将视频标记为未关闭，建立一个定时器反复去执行这些动作。
        //如果要执行之前视频的记录保存，那么关闭轮巡的关闭方法就需要重新写，或者关闭的时候加一个参数去判断。
        
        //云台就是调用 dataHolder方法
        /**
         * 执行轮巡
         */
        startPoll: function(array,time) {
        	if (!array || array.length == 0) {
        		promptAlarm('请选择视频设备！');
        		return false;
        	}
        	
        	time = $.isNumeric(time) ? time : this._opts.pollInterval;
        	this._pollArray = array;
        	var me = this,
        		windowNum = me._opts.windows,
        		maxNum = array.length,
        		nowNum = 0 ;
        	me.saveList();
        	
        	this._polltimer = new PollTimer(function(firstRun){
        	    me.closeAll();
        	    for(var i = 0; i < windowNum; i++) {
        	        if(nowNum == maxNum){
        	            nowNum = 0;
        	            if(maxNum < windowNum) {
        	                break;
        	            }
        	        }
        	        
        	        me.playByOrder(array[nowNum].video, array[nowNum].id, array[nowNum].opts);
        	        nowNum++;
        	    }
        	    if (firstRun) {
        	        me.dispatch('startpoll', array);
        	    }
        	}, time);
        },
        
        /**
         * 结束轮巡
         */
        stopPoll: function() {
        	if(!this._polltimer){
        		return;
        	}
        	this._polltimer.stop();
        	this._polltimer = undefined;
        	console.log('------> 轮巡结束 <-------');
        	this.dispatch('stoppoll', {});
        	//恢复之前打开的视频
        	this.playSaveList();
        },
        
        /**
         * 获取是否在轮巡
         */
        isPolling: function() {
        	return !!this._polltimer;
        },
        
        /**
         * 云台控制
         * up  				上
         * down				下
         * left				左
         * right			右
         * upleft			上左
         * upright			上右
         * downleft			下左
         * downright		下右
         * zoomin			倍率变大
         * zoomout			倍率变下
         * focusnear		焦点+
         * focusfar			焦点-
         * irisopen			光圈+
         * irisclose		光圈-
         * pointset			设置预置点
         * pointdel			删除预置点
         * pointgoto		到预置点
         * scansetleft		自动扫描左边界
         * scansetright		自动扫描又边界
         * scansetspeed		设置扫描速度
         * scanrun			自动扫描运行
         * cruiseadd		添加巡航点
         * cruisedel		删除巡航点
         * cruisespeed		设置巡航点速度
         * cruisepausetime	设置巡航滞留时间
         * cruiserun		启动巡航
         */
        holder: function(type, opts, isStop) {
        	var index = this._getChoiceWindow();
        	if( !this.videoStatus[index] ){
        		promptAlarm('未选中播放的视频！');
        		return;
        	}
        	
        	var holdType = 'up down left right upleft upright downleft downright zoomin zoomout focusnear focusfar irisopen irisclose pointset pointdel pointgoto '+
			'scansetleft scansetright scansetspeed scanrun cruiseadd cruisedel cruisespeed cruisepausetime cruiserun';
        	
        	var typeVal = (Number(holdType.split(' ').indexOf(type))+Number(1));
        	console.log("holdType：" + typeVal + " type：" + type + (isStop ? ' 停止' : ''));
        	
        	if (!typeVal || typeVal <= 0) {
        		console.error('异常PTZ指令：'  + typeVal);
        	}
        	
    		var video = this.videoStatus[index].video;

        	if(isStop) {
        		//var playerId = this._obj.SCWebGetCurrentPlayID();
        		var result = this._obj.SCWebPTZControl(video,1,typeVal,0,0,0,0);
        		//var result = this._obj.SCWebPTZControlEx(playerId, 4, 1, 1);
        		console.log(">>>>yuntai control,stop, video=" + video + ", result=" + result);
        		return;
        	}
        	var _opts = {
        			speed: 200,
        			group: 0,
        			present: 0,
        			time:0
        	}
        	$.extend(_opts,opts);
        	this._obj.SCWebPTZControl(video, 0, 
        			typeVal, _opts.speed, _opts.group, _opts.present, _opts.time);
        	console.log('设备号：'+ video +', 云台移动-->'+ type);
        },
        
        /**
         * 视频回放
         * @param startTime [YYYY-MM-DDTHH:mm:ss]
         * @param endTime
         * @return playId
         */
        playHistory: function(video,startTime,endTime,opts) {
        	return this._obj.SCWebHistoryPlay(video,startTime,endTime);
        },
        
        /**
         * 历史流控制
         * @param  {number} playId    
         * @param  {string} playType  播放类型（play && pause）
         * @param  {numner} playSpeed 播放速率
         * @param  {string} startTime 回放时间（暂时无用）
         */
        historyControl: function(playId, playType, playSpeed, startTime) {
        	var contorlType = {
    			play: 1,
    			pause: 2
        	};
        	
        	var playCommand = contorlType[playType];
        	if (!playCommand) {
        		console.error('unsupported type: ', playType);
        		return;
        	}
        	
        	this._obj.SCWebHistoryControl(playId, playCommand, playSpeed, startTime);
        },
        
        /**
         * 历史流控制（原）
         */
        _historyControl: function(playId,type,speed,startTime) {
        	var contorlType = {
        			normal: 1,
        			pause: 2,
        			'continue': 3,
        	};
        	var commad = 1;
        	
        	type == 'speed' ? speed && speed < 1 ? (commad = 7 , speed = 1/speed) : commad = 6
        					: commad = contorlType[type];
        	
        	this._obj.SCWebHistoryControl(playId,commad,speed);
        	
        },
        
        /**
         * 跳转历史流
         */
        skipHistory: function(playId,time) {
        	this._obj.SCWebHistorySeekPlay(playId,time);
        },
        
        /**
         * 抓图
         * @return 0:失败|1：成功
         */
        capturePicture: function(playId) {
        	var videoCapImagePath = this._opts.videoCapImagePath ? this._opts.videoCapImagePath : '';
        	return this._obj.SCWebCapturePicture(playId, videoCapImagePath, '');
        },
        
        
        saveList: function() {
        	this._saveList = cloneObj(this.videoStatus);
        },
        
        playSaveList: function() {
        	if (!this._saveList) {
        		return;
        	}
        	this.closeAll();
        	var me = this;
        	$.each(this._saveList,function(index,obj){
        		me.play(index, obj.video, obj.id, obj.opts);
        	});
        },
        
        /**
         * 获取当前选择窗口的视频video
         */
        getInChoiceVideo: function() {
        	return this.videoStatus[this._obj.SCWebGetCurrentWindowIndex()];
        },
        
        /**
         * 获取当前选择的窗口的playId
         */
        getInChoicePlayId: function() {
        	return this._obj.SCWebGetCurrentPlayID();
        },
        
        /**
         * 设置全屏
         */
        setFullScreen: function() {
        	this._obj.ScWebFullScreen(1);
        },
        
        /**
         * 获取当前视频控件的配置项
         */
        getVideoControllerOpts: function() {
        	return this._opts;
        },
        
        /**
		 * 添加事件
		 */
		addListener: function(type,handler,key){
			videoListener.addListener(type,handler,key);
		},
		
		/**
		 * 删除事件
		 */
		removeListener: function(type,handler){
			videoListener.removeListener(type,handler);
		},
		/**
		 * 派发事件
		 */
		dispatch: function(e,options){
			videoListener.dispatch(e,options);
		},
		
      	/*
    	 * 总的初始化
    	 * 参数示例：			
    	 * var opts = {
	                windows: 4,   //初始化的窗口数
	                conf: {       //配置参数
	                	user: conf['video.username'],   //用户名
	                	passwd: conf['video.password'], //密码
	                	ip: conf['video.ip'],           //videoServer ip
	                	port: conf['video.port'],       //videoServer port
	                	token : token                   //通讯录令牌，若token非空，则用户名和密码可不传
	                },
	                extra: false,
	                streamType: 0,                  //码流类型 默认0
	                openChangeWindowStrategy: true, //打开策略，切屏:属性为true，则当从大分屏切换到小分屏的时候会保留被关闭的视频，如果未设置 则不保留
	                capImage: true,                 //是否截屏:属性为true的时候，视频上会浮现控制条，进行截图、云台控制操作
	                videoCapImagePath: conf['video.cap.image.path'] //截屏默认保存的地址
	                pollInterval: 30                //轮巡时间，单位秒
			};
    	 */
        _init: function($dom,opts){
        	var me = this;
        	//配置项
            me._opts = {
                windows: 4,
                conf: {},
                extra: false,
                ocxName: '__videoDiv',
                streamType: 0,
                openChangeWindowStrategy: false,
                capImage: false,
                videoCapImagePath: '',
                pollInterval: 10
            };         
            
            $.extend(me._opts,opts);
            var windowsArr = me._opts.windowsArr;
            if (!windowsArr || windowsArr.length == 0) {
            	me._windowList = {1:{}, 4:{}, 6:{}, 9:{}, 16:{}}
            	me._windowsArr = [1, 4, 6, 9, 16];
            } else {
            	me._windowList = {};
            	for (var index in windowsArr){
            		var item = windowsArr[index];
            		me._windowList[item] = {};
            	}
            	me._windowsArr = windowsArr;
            }
            
            //me._windowList = {1:{},2:{},3:{},4:{}}
            
            if (!$.isNumeric(me._opts.pollInterval)) {
            	console.error('pollInterval should be number');
            	return;
            }
        	
            //事件注册区域
            me._addStopHandler();
            me._addClickHandler();
            me._addHishandler();
            
            //浏览器刷新/关闭前执行
            me._beforeUnload();
            
        	//当前视频窗口的值
            me.videoStatus = {};
            //不可关闭的窗口
            me._disableClosed = new Array();
            //动态生成monitor对象
        	me._obj = $('<OBJECT>').attr({
            	id: me._opts.ocxName,
            	name: me._opts.ocxName,
            	classid: 'clsid:5D62BFBF-7B2D-4E9E-A359-5228400C77BC',
            	width: '100%',
            	height: '100%'
            });
            $dom.append(me._obj);
            
            me._obj = me._obj[0];

            
            var conf = me._opts.conf;
            //初始化和登录
            var init = me._obj.ScWebDecoderInit(0);
            console.log('init：' + init);
            //是否开启抓图
            
            
            var login;
            if(conf.token && conf.token.length > 0 && me._obj.SCWebDecoderLoginInVS_Token) {
            	login = me._obj.SCWebDecoderLoginInVS_Token(conf.token, conf.ip, conf.port);
            } else {
            	login = me._obj.SCWebDecoderLoginInVs(conf.user, conf.passwd, conf.ip, conf.port);
            }
            console.log('login：' + login);
            
            //调整分屏模式
            setTimeout(function(){
            	//设置云台抓图控制按钮
            	me._opts.capImage && me._obj.SCWebSetPtzButtonLayout('');
            	
                me._opts.extra
                ? me._obj.SCWebDecoderSetExtraScreenMode(me._opts.windows)
                : me._obj.SCWebDecoderSetScreenMode(me._opts.windows);
		    }, 100);
            
        },
        
        /**
         * TODO 添加注释
         */
        _getTipObj: function() {
            var obj = {};
            var fncName = 'play playByOrder playAll playInChoice playMulWindows click getWindowsNum setWindowsNum',
            	fncName2 = 'isPlaying setChoiceWindow close closeAll enableClosede disableClosed addListener removeListener dispatch';
            $.each(fncName.split(' '),function(i,name) {
                obj[name] = function() {
                    alert('不支持非IE环境');
                }
            });
            $.each(fncName2.split(' '),function(i,name) {
                obj[name] = function() {
                    console.log('不支持非IE环境');
                }
            });
            obj.type = 'disable';
            return obj;
        },
        
        /**
         * 获取编号最小的空闲窗口的编号
         */
        _getMinIndexFreeWindow: function(searchedZoom) {
        	searchedZoom = searchedZoom || 0;
        	var index = Math.ceil(Math.pow(searchedZoom,2));
        	for (; index < this._opts.windows ; index++) {
        		if (!this.videoStatus[index]) {
        			return index;
        		}
        	}
        	return -1;
        },
        
        /**
         * 获取选择的窗口的编号
         */
        _getChoiceWindow: function(){
//        	var playId = this._obj.SCWebGetCurrentPlayID();
//        	var index;
//        	if (playId > 0) {
//        		index = this._obj.SCWebGetRealPlayWindows().split(',')[0];
//        		this.setChoiceWindow(index ? index : 0);
//        	}
//        	return index;
        	return this._obj.SCWebGetCurrentWindowIndex();
        },
        
        /**
         * 切换分屏
         */
/*        _changeWindowsAction: function(num) {
        	var me = this,
        		old = me._opts.windows,
        		now = num,
        		oldZoom = Math.sqrt(old),
        		nowZoom = Math.sqrt(now);
        	if (old == now) {
        		return;
        	}
        	if (me._opts.openChangeWindowStrategy) {
        		if (old > now) {
            		for (; now < old ; now++) {
            			var tempZoom = Math.ceil(Math.sqrt(now+1));

            			me.videoStatus[now] && (me._windowList[tempZoom][now] = {
					            					video: me.videoStatus[now].video,
					            					id: me.videoStatus[now].id,
					            					opts: me.videoStatus[now].opts,
                								},
                								me.close(now));
            		}
            			
            	} else {
            		while (oldZoom < nowZoom) {
            			oldZoom = oldZoom+1;
            			me._windowList[oldZoom] && $.each(me._windowList[oldZoom],function(index,obj) {
            				me.play(index, obj.video, obj.id, obj.opts);
            			});
            			me._windowList[oldZoom] = {};
            		}
            	}
        	} else {
        		if (old > now) {
            		for (; now < old ; now++) {
            			me.videoStatus[now] && me.close(now);
            		}
        		}
        	}
        },*/
        
        /**
         * 切换分屏
         */
        _changeWindowsAction: function(num) {
        	var me = this,
        		old = me._opts.windows,
        		now = num;
//        		oldZoom = Math.sqrt(old),
//        		nowZoom = Math.sqrt(now);
        	if (old == now) {
        		return;
        	}
        	if (me._opts.openChangeWindowStrategy) {
        		if (old > now) {
            		for (; now < old ; now++) {
            			//var tempZoom = Math.ceil(Math.sqrt(now+1));
            			var tempZoom = me._getWindowsNum(now + 1);
        
            			me.videoStatus[now] && (me._windowList[tempZoom][now] = {
					            					video: me.videoStatus[now].video,
					            					id: me.videoStatus[now].id,
					            					opts: me.videoStatus[now].opts,
                								},
                								me.close(now));
            		}
            			
            	} else {
            		while (old < now) {
            			old =  me._getNextWindowsNum(old);
            			me._windowList[old] && $.each(me._windowList[old],function(index,obj) {
            				me.play(index, obj.video, obj.id, obj.opts);
            			});
            			me._windowList[old] = {};
            		}
            	}
        	} else {
        		if (old > now) {
            		for (; now < old ; now++) {
            			me.videoStatus[now] && me.close(now);
            		}
        		}
        	}
        },
        
        /**
         * 获取当前的分屏数
         * now为当前窗口的编号
         */
        _getWindowsNum: function(now) {
        	var me = this;
        	var windowsArr = me._windowsArr;
        	for (var index in windowsArr){
        		if (now <= windowsArr[index]) {
        			return windowsArr[index];
        		}
        	} 	
        },
        
        /**
         * 获取下一窗口
         */
        _getNextWindowsNum: function(old) {
        	var me = this;
        	var windowsArr = me._windowsArr;
        	for (var index in windowsArr){
        		if (index == windowsArr.length - 1) {
        			return windowsArr[index]
        		}
        		if (old == windowsArr[index]) {
        			return windowsArr[Number(index) + Number(1)];
        		}
        	}
        },
        
        _addStopHandler: function() {
        	var me = this;
			window.stopVideo = function(playId,videoId) {
				me.close(me.getWindowByPlayId(playId));
				me.dispatch('streamoff');
			};
			me._regEvent('SCWebStopVideoEvent(playId,videoId)', 'stopVideo(playId,videoId);');

        },
        
        _addClickHandler: function() {
        	var me = this;
			window.clickVideo = function(playId) {
				me.dispatch('click',me.videoStatus[me.getWindowByPlayId(playId)]);
			};
			me._regEvent('SCWebDecoderClick(playId,type)', 'clickVideo(playId);');
        },
        
        _addHishandler: function() {
        	var me = this;
        	window.playbackVideo = function(playId,videoId,historytime) {
				me.dispatch('playback',{playId:playId,videoId:videoId,historyTime:historytime});
			};
			me._regEvent('SCWebHistoryPlayTime(playId,videoId,historytime)', 'playbackVideo(playId,videoId,historytime);');
        },
        
        _regEvent: function(eventName,handlerName) {
        	window._addScriptFlag = true;
        	var script;
			try {
				script = $('<script>').attr({
					'for': this._opts.ocxName,
					'event': eventName,
				}).text('if (!_addScriptFlag) {'
						+handlerName
						+'}'
						+'_addScriptFlag = false;');

			} catch (e) {
				script = '<script for="'+this._opts.ocxName+'" event = "'+eventName+'" >'
							+'if (!_addScriptFlag) {'
								+handlerName
							+'}'
							+'_addScriptFlag = false;'
						+'</script>';
			}
			$('body').append(script);
        },
        
        _beforeUnload: function() {
        	var me = this;
        	window.onbeforeunload = function (e) {
        		me.closeAll();
        		me._obj.SCWebDecoderDestroy();
        	};
        },

    }
    
    /**
     * 使用webRtc方式的video工具类
     */
    function VideoWebRtc($dom,opts){ 
        if (!opts) {
        	console.error('VideoWebRtc的参数opts不能为空');
            return;
        }
    	this._init($dom,opts);
    }
    
    /**
     * 使用WEB-RTC方式的视频播放的方法
     */
    VideoWebRtc.prototype = {
    	constructor: VideoWebRtc,
    	
    	VIDEO_DATA: [], //记录视频各分屏的状态
   
        /**
         * 播放视频
         * 参数：index(视频窗口编号，从0开始) video(视频设备id，即devId) id(标识，空的话使用设备id) opts(其他参数)
         * 返回true/false
         */
        play: function(index, video, id, opts){
        	var me = this;
        	if (me.isPlaying(id) != -1) {
        		console.info('该视频正在播放');
        		return false;
        	}
            console.log("play >>> " + "video=" + video + "; id=" + id + "; index=" + index);
            me.dispatch('beforeplay',{index:index, video:video, id:id});
            
            if (index < 0) {
            	console.error('index参数错误');
            	return false;
            }
            me.VIDEO_DATA[index].play(video);
            
            opts = opts || {};
            
            if (me.VIDEO_DATA[index].playing) {
            	me.VIDEO_DATA[index].opts = opts;
            	me.VIDEO_DATA[index].id = id;
            	me.dispatch('playsuccess', me.VIDEO_DATA[index]);
            	return true;
            }
            return false;
        },
    	
        /**
         * 在序号最小的空闲窗口播放视频
         * 参数：index(视频窗口编号，从0开始) video(视频设备id，即devId) opts(其他参数)
         * 返回true/false
         */
        playByOrder: function(video, id, opts){
            var freeWindow = this._getMinIndexFreeWindow();
            
            if(freeWindow == -1){
			    return this.playInChoice(video, id, opts);
		    }
		    return this.play(freeWindow, video, id, opts);
        },
        
        /**
         * 扩展视频窗口数的播放方式
         */
        playByOrderExpandWindow: function(video, id, opts){
        	var me = this;
        	
        	var freeWindow = this._getMinIndexFreeWindow();   
        	
//        	while (this._opts.windows < 16 && freeWindow == -1) {
//         		me.setWindowsNum(me._getNextWindowsNum(parseInt(me._opts.windows)));
//        		freeWindow = this._getMinIndexFreeWindow(0);
//        	}
        	
        	while (freeWindow == -1) {
        		var zoom = Math.sqrt(this._opts.windows*1)+1;
        		
        		if (this._opts.windows == 6) {
        			this.setWindowsNum(9);
        		} else {
            		this.setWindowsNum(Math.pow(zoom,2));
        		}
        		
        		freeWindow = this._getMinIndexFreeWindow(zoom-1);
        	}
        	
        	if (this._getChoiceWindow() == -1 && this._getMinIndexFreeWindow() != -1) {
        		this.setChoiceWindow(this._getMinIndexFreeWindow());
        	}
        	
        	if(freeWindow == -1 || 
        			(this._getChoiceWindow() != -1 && !this.getInChoiceVideo() && this._opts.windowsNum > 1)){
			    return this.playInChoice(video,id,opts);
		    }
        	
		    return this.play(freeWindow, video, id, opts);
        },
        
        /**
         * 播放所有视频
         */
        playAll: function(array){
            if (array.length > this._opts.windows) {
                throw new Error('windows is not enough');
            }
            var me = this;
            me.closeAll();
            $.each(array,function(i,obj){
                me.play(i, obj.video, obj.id, obj.opts);
            });
        },
        
        /**
         * 在鼠标选中的窗口中播放视频
         */
        playInChoice: function(video, id, opts){
        	var me = this;
        	var selView = $('[video-flag="'+me._opts.windowsBeginIndex+'"]>li.sel');
        	if(selView.length){
        		if (me.VIDEO_DATA[selView.index()].playing) {
        			me.close(selView.index());
        	 		//延时打开  禁止同时一关一开
                    setTimeout(function(){
                    	me.play(selView.index(), video, id, opts);
        		    }, 1000);
        		} else {
        			me.play(selView.index(), video, id, opts);
        		}
    		}
        },
        
        /** 
         * 检索当前点的视频是否被播放，被播放则返回播放的视频窗口
         */
        isPlaying: function(id){
        	var me = this;
            var index = -1;
    	    $.each(me.VIDEO_DATA,function(key,val){
                if (id == val.id && me.VIDEO_DATA[key].playing) {
                    index = key;
                }
    	    });
    	    return index;
        },
        
        /**
         * 关闭指定窗口的视频
         */
        close: function(index, isSave){
        	if (index < 0) {
        		console.info('index参数错误');
        		return;
        	}
        	
        	this.VIDEO_DATA[index].close();
   
            if (!isSave) {
                this.dispatch('afterclose', this.VIDEO_DATA[index]); 
            }

        },
    	
        /**
         * 关闭所有视频
         */
        closeAll: function(isSave){
        	var me = this;
        	       	
			var openVideos = [];
			for(var i = me._opts.windowsBeginIndex; i < me._opts.windowsBeginIndex + me._opts.windowsNum; i++){
				if(me.VIDEO_DATA[i].playing){
					me.close(i, isSave)
				}
			}

//			if(!openVideos.length) return;
//			
//			//适当延时进行关闭
//			var count = 0;			
//			var interval = setInterval(function(){
//				if(count == openVideos.length){
//					clearInterval(interval);
//				}else{
//					me.close(openVideos[count], isSave)
//					count++;
//				}
//			}, 50);
        },
        
        /**
         * 设置鼠标选中窗口
         */
        setChoiceWindow: function(index) {
            $('.screen-' + (index + 1)).click();
        },
        
        /**
         * 获取视频窗口数
         */
        getWindowsNum: function() {
            return this._opts.windows;
        },
        
    	/**
    	 * 分屏切换，传入的参数为新的屏数
    	 */
    	setWindowsNum: function(num) {
    		var me = this;
    		
    		//切换屏幕后 选中空闲最小的窗口
    		if (me._opts.windows != num && me._getMinIndexFreeWindow() != -1) {
    			me.setChoiceWindow(me._getMinIndexFreeWindow());
    		}
    		
			$('[video-flag="'+me._opts.windowsBeginIndex+'"]').removeClass("mode-" + me._opts.windows).addClass("mode-" + num);
			var _li = $('[video-flag="'+me._opts.windowsBeginIndex+'"]>li').hide();
			me._opts.windows = num;
			for(var i = 0; i < num; i++){
				_li.eq(i).show();
			}
			//分屏切换事件
			this.dispatch('screenchange', {windowNums:num});
    	},
        
        /**
         * 询问是否无可用窗口
         */
        isUnavailable: function() {
        	return this._opts.windows == 16 && this._getMinIndexFreeWindow() == -1;
        },
        
        /**
         * 执行轮巡
         */
        startPoll: function(array,time) {
        	if (!array || array.length == 0) {
        		promptAlarm('请选择视频设备！');
        		return false;
        	}
        	
        	time = $.isNumeric(time) ? time : this._opts.pollInterval;
        	this._pollArray = array;
        	var me = this,
        		windowNum = me._opts.windows,
        		maxNum = array.length,
        		nowNum = 0 ;
        	me.saveList();
        	
        	this._polltimer = new PollTimer(function(firstRun){
        	    me.closeAll();
        	    for(var i = 0; i < windowNum; i++) {
        	        if(nowNum == maxNum){
        	            nowNum = 0;
        	            if(maxNum < windowNum) {
        	                break;
        	            }
        	        }
        	        
        	        me.playByOrder(array[nowNum].video, array[nowNum].id, array[nowNum].opts);
        	        nowNum++;
        	    }
        	    if (firstRun) {
        	        me.dispatch('startpoll', array);
        	    }
        	}, time);
        },
        
        /**
         * 结束轮巡
         */
        stopPoll: function() {
        	if(!this._polltimer){
        		return;
        	}
        	
        	this._polltimer.stop();
        	this._polltimer = undefined;
        	
        	console.log('------> 轮巡结束 <-------');
        	this.dispatch('stoppoll', {}); 
        	
        	this._pollArray = null;     	
        	this.closeAll();
        	//恢复之前打开的视频
        	//this.playSaveList();
        },
        
        /**
         * 获取是否在轮巡
         */
        isPolling: function() {
        	return !!this._polltimer;
        },
        
        holder: function(type, opts, isStop) {
        	var index = this._getChoiceWindow();
        	if (index < 0) {
        		promptFailed('请先选中视频');
				return false;
        	}
        	return this.VIDEO_DATA[index].holder(type, opts, isStop);        	
        },
        
        /**
         * 视频回放
         * @param startTime [YYYY-MM-DDTHH:mm:ss]
         * @param endTime
         * @return playId
         */
        playHistory: function(video, startTime, endTime, opts) {
        	var me = this;
        	
        	var index;       	
        	//回放是一分屏的默认使用一个窗口
        	if (me._opts.windowsNum == 1) {
        		index = me._opts.windowsBeginIndex;
        	} else {
        		index = me._getMinIndexFreeWindow();
        	}
        	
        	if (index < 0) {
        		console.error('窗口编号获取失败！')
        	}
        	
        	me.VIDEO_DATA[index].opts = opts;
        	return me.VIDEO_DATA[index].playback(video,startTime,endTime);
        },
        
        /**
         * 关闭历史流
         */
        closeHistory: function(index) {
        	var me = this;
        	
        	if (!index) {
	        	var index;
	        	if (me._opts.windowsNum == 1) {
	        		index = me._opts.windowsBeginIndex;
	        	}
        	}
        	
        	return me.VIDEO_DATA[index].close("stop");
        },
        
        /**
         * 历史流控制
         * @param  {number} video    
         * @param  {string} playType  播放类型（play && pause & stop）
         * @param  {numner} playSpeed 播放速率
         * @param  {string} startTime 回放时间（暂时无用）
         */
        historyControl: function(video, playType, playSpeed, startTime) {  
        	var me = this;
        	var index;
        	if (me._opts.windowsNum == 1) {
        		index = me._opts.windowsBeginIndex;
        	} else {
        		index = me._getChoiceWindow();
        	}
        	return me.VIDEO_DATA[index].playbackControl(video, playType, playSpeed, startTime);
        },
        
        saveList: function() {
        	this._saveList = cloneObj(this.VIDEO_DATA);
        },
        
        
        playSaveList: function() {
        	if (!this._saveList) {
        		return;
        	}
        	this.closeAll();
        	var me = this;
        	$.each(this._saveList, function(index, obj){
        		if (obj.video) {       		
            		me.play(obj.index, obj.video, obj.id, obj.opts);
        		}
        	});
        },
        
        /**
         * 获取当前选择窗口的视频video
         */
        getInChoiceVideo: function() {
        	var me = this;
        	var selView = $('[video-flag="'+me._opts.windowsBeginIndex+'"]>li.sel');
    		if(selView.length && me.VIDEO_DATA[selView.index()].video){
    			return me.VIDEO_DATA[selView.index()];
    		}
        	return undefined;
        },
        
        /**
         * 设置全屏
         */
        setFullScreen: function() {
        	this._fullScreenEvent(document.getElementById("video-main-web-rtc"));
        },
        /**
         * 获取当前视频控件的配置项
         */
        getVideoControllerOpts: function() {
        	return this._opts;
        },
        	
        /**
		 * 添加事件
		 */
		addListener: function(type,handler,key){
			videoListener.addListener(type,handler,key);
		},
		
		/**
		 * 删除事件
		 */
		removeListener: function(type,handler){
			videoListener.removeListener(type,handler);
		},
		/**
		 * 派发事件
		 */
		dispatch: function(e,options){
			videoListener.dispatch(e,options);
		},
		
        /**
         * 获取编号最小的空闲窗口的编号
         */
        _getMinIndexFreeWindow: function(index) {
        	var me = this;
        	index = index || me._opts.windowsBeginIndex;
        	for (; index < me._opts.windowsBeginIndex + me._opts.windows ; index++) {
        		if (!me.VIDEO_DATA[index].playing) {
        			return index;
        		}
        	}
        	return -1;
        },
       	
        /**
         * 获取选中的窗口的index
         */
        _getChoiceWindow: function() {
        	var me = this;
        	var selView = $('[video-flag="'+me._opts.windowsBeginIndex+'"]>li.sel');
        	if (selView.length) {
        		return selView.index();
        	}
        	return -1;
        },
        
        /**
         * 获取下一窗口
         */
        _getNextWindowsNum: function(old) {
        	var me = this;
        	var windowsArr = me._windowsArr;
        	for (var index in windowsArr){
        		if (index == windowsArr.length - 1) {
        			return windowsArr[index]
        		}
        		if (old == windowsArr[index]) {
        			return windowsArr[Number(index) + Number(1)];
        		}
        	}
        }, 
        
        /**
         * 设置鼠标选中窗口
         */
        _clickWindow: function() {
        	var me = this;
    		//视频窗口选中
    		$('[video-flag="'+me._opts.windowsBeginIndex+'"]>li').click(function(){
    			$('[video-flag="'+me._opts.windowsBeginIndex+'"]>li').removeClass("sel");
    			$(this).addClass("sel");
    			
    			//如果视频正在播放则分发点击消息
            	if (me.getInChoiceVideo()) {
            		me.dispatch('click', me.getInChoiceVideo());
            	}
    		}); 
        },
        
      	/*
    	 * 总的初始化
    	 * 参数示例：			
    	 * var opts = {
	                windows: 4,   //初始化的窗口数
	                conf: {       //配置参数
	                	user: 'admin',   //用户名
	                	passwd: '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b', //密码
	                	janusUrl: 'wss:  //192.168.103.226:8989', //janusServer服务地址
	                },
	                pollInterval: 30     //轮巡时间，单位秒
			};
    	 */
        _init: function($dom,opts){
        	var me = this;
        	//配置项
            me._opts = {
                windows: 4,
                conf: {},
                pollInterval: 10,
                windowsNum: 16
            };  
            
            $.extend(me._opts,opts);
            
            var windowsArr = me._opts.windowsArr;
            if (!windowsArr || windowsArr.length == 0) {
              	me._windowList = {1:{}, 4:{}, 6:{}, 9:{}, 16:{}}
            	me._windowsArr = [1, 4, 6, 9, 16];
            } else {
            	me._windowList = {};
            	for (var index in windowsArr){
            		var item = windowsArr[index];
            		me._windowList[item] = {};
            	}
            	me._windowsArr = windowsArr;
            }
            
            //获取起始的窗口位置
            me._opts.windowsBeginIndex = windowsSum;
            //窗口总数
            windowsSum += me._opts.windowsNum;
            
            //初始化界面
            me._initView($dom);
            //初始化Janus
            me._initJanus();
            //初始化按钮点击事件
            me._initBtnEvent();
            
            //设置鼠标点击选中窗口
            me._clickWindow();
            //显示视频信息：名称、分辨率、码率、丢包率
            me._showVideoInfo();
            //双击某个视频全屏
            me._dbClickFullScreen();
        },
        
        /**
         * 初始化按钮点击事件
         */
        _initBtnEvent: function() {
        	var me = this;
        	//接收音频事件
        	$("button[name='recvAudio']").click(function(){
        		var index = Number($(this).parent().parent().attr("index"));
        		
        		if (!me.VIDEO_DATA[index].playing) {
        			promptAlarm('请选择播放的视频源！');
        			return;
        		}
        		
        		if ($(this).attr('class') == 'recv-audio-btn') {
        			//发送停止播放音频的请求
        			me.VIDEO_DATA[Number(index)].operateAudio("stop_audio")       			
        			$(this).attr('class', 'unrecv-audio-btn');
        			me.VIDEO_DATA[Number(index)].videoBox.muted = false;
        		} else {     		       			
        			//发送播放音频的请求
        			me.VIDEO_DATA[Number(index)].operateAudio("recv_audio");       				
        			$(this).attr('class', 'recv-audio-btn');
        			me.VIDEO_DATA[Number(index)].videoBox.muted = true;
        		}      		
        	});
        	
        	//发送音频事件
//        	$("button[name='sendAudio']").click(function(){
//        		var index = Number($(this).parent().parent().attr("index"));
//        		
//        		if (!me.VIDEO_DATA[index].playing) {
//        			promptAlarm('请选择播放的视频源！');
//        			return;
//        		}
//        		
//        		if ($(this).attr('class') == 'send-audio-btn') {
//        			//发送停止发送音频的请求
//        			me.VIDEO_DATA[Number(index)].operateAudio("unsend_audio")    
//        			$(this).attr('class', 'unsend-audio-btn');
//        		} else {         			
//        			//发送播放音频的请求
//        			me.VIDEO_DATA[Number(index)].operateAudio("send_audio")  
//        			$(this).attr('class', 'send-audio-btn');
//        		}      		
//        	});
        },
        
        /**
         * 双击某个视频全屏
         */
        _dbClickFullScreen: function() {
        	var me = this;
            $('[video-flag="'+me._opts.windowsBeginIndex+'"]').find('.video-box').on("dblclick",function(){
            	me._fullScreenEvent(this);
            });
        },
        
        /**
         * 全屏事件
         */
        _fullScreenEvent: function(el) {
        	var isFullscreen = el.fullScreen || el.mozFullScreen || el.webkitIsFullScreen;
        	if(!isFullscreen){//进入全屏,多重短路表达式
	        	(el.requestFullscreen && el.requestFullscreen()) ||
	        	(el.mozRequestFullScreen && el.mozRequestFullScreen()) ||
	        	(el.webkitRequestFullscreen && el.webkitRequestFullscreen()) || (el.msRequestFullscreen && el.msRequestFullscreen());
        	}
        	
        	//关闭全屏
//        	colseFullscreen();        	
//        	function colseFullscreen() {
//	        	el.onmouseup = function(e){     //在body里点击触发事件
//	                if(e.button === 0){       
//	                	document.exitFullscreen?document.exitFullscreen():
//	                	document.mozCancelFullScreen?document.mozCancelFullScreen():
//	                	document.webkitExitFullscreen?document.webkitExitFullscreen():'';	                	
//	                }
//	            }
//        	}
        },
        
        /**
         * 在视频界面上显示视频的信息 码率、分辨率、丢包率
         */
        _showVideoInfo: function() {
        	var me = this;
            function clock(){
                for (var i = 0; i < me.VIDEO_DATA.length; i++) {
                	if (me.VIDEO_DATA[i].playing) {
                		var number = Number(i) + Number(1);
                		var videoObj = document.getElementById('video-' + number);
                		
                		var width = videoObj.videoWidth;
                		var height = videoObj.videoHeight;
  
                 		//码率     
                		var bitrate = me.VIDEO_DATA[i].sipcall.getBitrate();
                   		if (width == 0 || !bitrate || bitrate.indexOf("kbits") == -1) {
                			continue;
                		}
                		
                		var config = me.VIDEO_DATA[i].sipcall.webrtcStuff;
                		me._setPacketsLostRate(i, config, me);
                		
                		var videoInfoObj = document.getElementById('info-' + number);
                		var videoName = me.VIDEO_DATA[i].opts && me.VIDEO_DATA[i].opts.name ? 
                				me.VIDEO_DATA[i].opts.name : me.VIDEO_DATA[i].video;
                		videoInfoObj.innerHTML = videoName + '&nbsp;&nbsp;' + width + "×" + height +
                				'<br>' + bitrate + '&nbsp;&nbsp;Lost：' + me.VIDEO_DATA[i].packetsLostRate;
                	}              	
                }
            }
            var timer = setInterval(clock, 1000);
        },
        /**
         * 获取设置丢包率
         */
        _setPacketsLostRate: function(index, config, me) {
    		if(config.pc != null && config.pc != undefined && config.pc.getStats) {              			
        		config.pc.getStats().then(function(stats) {
					stats.forEach(function (res) {
						if(!res) {
							return;
						}
						var inStats = false;
						// Check if these are statistics on incoming media
						if((res.mediaType === "video" || res.id.toLowerCase().indexOf("video") > -1) &&
								res.type === "inbound-rtp" && res.id.indexOf("rtcp") < 0) {
							// New stats
							inStats = true;
						} else if(res.type == 'ssrc' && res.bytesReceived &&
								(res.googCodecName === "VP8" || res.googCodecName === "")) {
							// Older Chromer versions
							inStats = true;
						}
						// Parse stats now
						if(inStats) {
							if (res.hasOwnProperty("packetsLost")) {
								//console.info('丢包率：' + res.packetsLost);
								if (!res.packetsLost || isNaN(res.packetsLost) || Number(res.packetsLost) == '0') {
									me.VIDEO_DATA[index].packetsLostRate = 0;
								} else {
									var packetsLost = Number(res.packetsLost) - Number(me.VIDEO_DATA[index].packetsLostSum);
									var packetsReceived = Number(res.packetsReceived) - Number(me.VIDEO_DATA[index].packetsReceivedSum);

									me.VIDEO_DATA[index].packetsLostSum = res.packetsLost;
									me.VIDEO_DATA[index].packetsReceivedSum = res.packetsReceived;
									var packetsLostRate = (Number(packetsLost) / (Number(packetsLost) + Number(packetsReceived))) * 100;
									me.VIDEO_DATA[index].packetsLostRate = packetsLostRate.toFixed(2) + '%';
								}
								//window.VIDEO_DATA[index].packetsLostRate = (Number(res.packetsLost) / (Number(res.packetsLost) + Number(res.packetsReceived))) * 100;
/*   					               		videoInfoObj.innerHTML = videoName + '&nbsp;&nbsp;' + width + "×" + height +
                				'<br>' + bitrate + '&nbsp;&nbsp;Lost：' + res.packetsLost;*/
							}
						}

					});
				});                		
    		}
        },
        
        /**
         * 界面的初始化，在传过来的dom中创建界面
         */
        _initView: function($dom) {
        	var me = this;
        	var objClass = (me._opts.windowsNum == 1 ? 'video-main-full mode-' : 'video-main mode-') + me._opts.windows;
        	var videoHtml = '<ul class="' + objClass +'" id="video-main-web-rtc" video-flag="'+me._opts.windowsBeginIndex+'">';
        	var index = me._opts.windowsBeginIndex + 1;
        	for (var i = index; i < index + me._opts.windowsNum; i++) {
        		videoHtml += '<li class="screen-' + i +'" index="' + (i - 1) +'"><video class="video-box" id="video-' + i +'" autoplay ></video>' +
        		'<div class="info hide" id="info-' + i +'"></div>' +
        		'<div class="audio hide">';
        		!checkIsHttp() && (videoHtml += '<button type="button" class="unsend-audio-btn" name="sendAudio"></button>');
        		videoHtml += '<button type="button" class="unrecv-audio-btn" name="recvAudio"></button>' +
        		'</div>' + 
        		'</li>';
        	}
        	videoHtml += '</ul>' ;
        	$dom.append(videoHtml);
        	
        	me.setWindowsNum(me._opts.windows);
        },
        
        /**
         * Janus的初始化
         */
        _initJanus: function(){
        	var me = this;
        	
//        	if (window.parent && window.parent.janus) {
//        		me._initSVideo(window.parent.janus);
//        		return;
//        	}
        	
    		Janus.init({debug:"error", callback: function(){
    			if(!Janus.isWebrtcSupported()) {
    				alert("不支持WEB-RTC");
    				return;
    			}
    			var janus = new Janus({
    				server: me._opts.conf.janusUrl,
    				success: function(){
    					console.log("janusServer连接成功");
    					me._initSVideo(janus);
    				},
    				error: function(error) {
    					alert('连接失败：'+ error);
    				},
    				destroyed: function() {
    					
    				}
    			});	
    			
    		}});
    	},
        /**
         * 初始化插件、登陆，初始化窗口
         */
    	_initSVideo: function(janus){
    		var me = this;
    		
    		//已经初始化过，则直接拿来用
//    		if (janus && (registered  || (window.parent && window.parent.registered))) {
//				//生成主界面
//				for(var i = me._opts.windowsBeginIndex; i < me._opts.windowsBeginIndex + me._opts.windowsNum; i++){
//					me.VIDEO_DATA[i] = new SVideo({
//						index:i,
//						janus:janus
//						
//					});
//				}			
//				return;
//    		}
    		
    		//初始化一个插件，用来登陆，不能用此插件播放视频。
    		var _loginSipCall = null;
    		janus.attach({
    			plugin: "janus.plugin.sip",
    			opaqueId: "siptest-" + Janus.randomString(12),
    			success: function(pluginHandle) {
    				console.log("janus登陆插件初始化成功");					
    				_loginSipCall = pluginHandle;
    				var register = {
    					"request" : "register",
    					"username" : me._opts.conf.user,
    					"secret": me._opts.conf.passwd,
    				};
    				_loginSipCall.send({"message": register});
    			},
    			error: function(error) {
    				console.error("janus登陆插件初始化失败");	
    			},
    			onmessage: function(msg, jsep) {
       				if (msg.error_code) {
    					console.error(msg.error)
						promptFailed(FAILED_CODE[msg.error_code] || '错误码：' + msg.error_code);
						return false;
    				}
       				
    				var result = msg["result"];
    				var event = result["event"];
    				
					if (result.error_code && result.error_code != 0) {
						promptFailed(FAILED_CODE[result.error_code] || '错误码：' + result.error_code);
					}
					
    				if(result !== null && result !== undefined && result["event"] !== undefined && result["event"] !== null) {
    					console.log("result event:" + event);
    					if(event === 'registration_failed') {
    						promptFailed("janus登陆失败: " + result["code"] + " " + result["reason"]);
    						return;
    					}
    					if(event === 'registered') {
    						userToken = result["userToken"];
    						console.log('janus登陆成功')
    						registered = true;

    						//生成主界面
    						for(var i = me._opts.windowsBeginIndex; i < me._opts.windowsBeginIndex + me._opts.windowsNum; i++){
    							me.VIDEO_DATA[i] = new SVideo({
    								index:i,
    								janus:janus
    								
    							});
    						}
    					}
    				}
    			}
    		});
    	},
          
    }
       
	var FAILED_CODE = {
    		1001 : "账号或密码错误",
    		1002 : "该帐号已连接",
    		1004 : "没有鉴权",
    		2001 : "未携带token或token错误",
    		2002 : "视频源id不存在",
    		2003 : "操作指令非法(该账号不允许执行这个指令，或者不支持该指令)",
    		3001 : "nat通道未建立",
    		3002 : "该视频流已在传输",
    		3003 : "无法获取远端视频流",
    		4001 : "视频流断开连接",
    		4002 : "获取视频失败",
    		5000 : "内部错误",
    		8001 : "设备不支持该指令",
    		453  : "videoServer连接失败",
    		454  : "录像回放窗口已占用，请先停止播放",
    		455  : "无视频录像，操作失败"
    }
    //window.VIDEO_DATA = [];//记录视频各分屏的状态
    window.windowsSum = 0; //当前页面的视频总数，可能有多个VideoWebRtc对象
	var userToken = null;
	var registered = false;
    
    function SVideo (opts) {
		this.janus = opts.janus;	
		this.sipcall = null;
		this.index = opts.index;
		this.videoBox = $('#video-' + (this.index + 1));
		this.init();
	}
    
    /**
     * 使用web-rtc方式的视频播放
     */
	SVideo.prototype = {
			
			/**
			 * 初始化
			 */
    		init:function(){
    			var self = this;

    			self.janus.attach({
    				plugin: "janus.plugin.sip",
    				opaqueId:"siptest-" + Janus.randomString(12),
    				
    				success: function(pluginHandle) {
    					console.log("视频插件初始化成功:" + self.index);					
    					self.sipcall = pluginHandle;
    				},
    				
    				error: function(error) {
    					console.error("插件初始化失败");	
    				},
    				
					consentDialog: function(on) {
						console.log("Consent dialog should be " + (on ? "on" : "off") + " now");
					},
					
    				onmessage: function(msg, jsep) {
    					if(!registered) {
    						promptFailed("请先登陆");
    					} 
    					
        				if (msg.error_code) {
        					console.error(msg.error)
    						promptFailed(FAILED_CODE[msg.error_code] || '错误码：' + msg.error_code);
    						return false;
        				}
        				
    					var result = msg["result"];
    					var event = result["event"];
    					
						if (result.error_code && result.error_code != 0) {
    						videoListener.dispatch('afterclose', self); 
    						
    						//播放失败
    						self.sipcall.hangup();//插件挂断
    						self.videoBox.hide();//视频窗video标签隐藏
    						self.playing = false;//缓存数据-是否播放视频置否
    						self.video = null;//缓存数据-视频video置空
    						self.packetsLostRate = 0;//丢包率 每秒刷新
    						self.packetsLostSum = 0;//丢包数
    						self.packetsReceivedSum = 0;//接收数
    						
    			       		//隐藏视频信息
    						self.videoBox.parent().find('.info').hide();
    			       		//隐藏音频喇叭
    						self.videoBox.parent().find('.audio').hide();
    						self.videoBox.parent().removeClass("loading").find(".stream-loading").remove();//移除loading标签
							
    						promptFailed(FAILED_CODE[result.error_code] || '错误码：' + result.error_code);
						}
						
						switch(event) {
							//即将播放视频 
							case 'incomingcall':
		   						self.sipcall.createAnswer({
	    							jsep: jsep,
	    							media: { audioSend: !checkIsHttp(), videoSend:false, audioRecv: true , videoRecv: true },
	    							success: function(jsep) {
	    								var body = { 
	    									request:"accept",
	    									videoidentify:result["videoidentify"],
	    									playseq:parseInt(result["playseq"]) 
	    								};
	    								self.sipcall.send({"message": body, "jsep": jsep});	    								
	    							},
	    							error: function(error) {
	    								console.error(error);
	    								var body = { "request": "decline", "code": 480 };
	    								self.sipcall.send({"message": body});
	    							}
	    						});
						        break;
						    //呼叫失败  
						    case 'callfaild':
	    						//promptFailed(FAILED_CODE[result.error_code] || '错误码：' + result.error_code);
						        break;
						    //云台    
						    case 'ptz':
						    	break;
						    //历史流控制	
						    case 'av_control':
						    	break;						    	
						    default:
						    	console.log('event：' + event);
						    	break;
						}
    				},
    				
    				onremotestream: function(stream) {
    					console.log('onremotestream：分屏=' + (self.index + 1) + ', video='  + self.video);				
    					Janus.attachMediaStream(self.videoBox.get(0), stream);
    				},
    				
    				onlocalstream: function(stream) {
    					//Janus.attachMediaStream(self.videoBox.get(0), stream);
    					
    					//var s = stream.getAudioTracks()[0];
    					//stream.removeTrack(s);    					
//    					self.sipcall.webrtcStuff.myStream.addTrack(s);  					
//    					self.sipcall.webrtcStuff.myStream.removeTrack(s);
   		
    					var btnObj = self.videoBox.parent().find("button[name='sendAudio']");
    					btnObj.unbind('click');   					
    					stream.getAudioTracks()[0].enabled = false;
    					
    					btnObj.click(function() {
    						if (btnObj.attr('class') == 'send-audio-btn') {
    							stream.getAudioTracks()[0].enabled = false;
    							self.operateAudio("unsend_audio");
    							btnObj.attr('class', 'unsend-audio-btn');    							
    						} else {
    							stream.getAudioTracks()[0].enabled = true;
    							self.operateAudio("send_audio");
    							btnObj.attr('class', 'send-audio-btn');
    						}   						
						}); 					
    					//stream.getTracks().forEach(track => track.stop());
    					console.log('onrelocalstream：分屏=' + (self.index + 1) + ', video='  + self.video);
    				},
    				
    				oncleanup: function() {
    					console.log('oncleanup：分屏=' + (self.index + 1));			
    				}
    			});

    			//<video>注册playing/canplay事件，用于判断视频播放成功
    			self.videoBox.bind("canplay play playing", function () {
    				if(self.video){
    					if (self.videoBox.is(':visible')) return;
    					
    					console.log('分屏=' + (self.index + 1) + ', ' + self.video + ' 播放成功');
    					promptSuccess('分屏' + (self.index + 1) + ' 播放成功');
    					self.videoBox.show();
    					self.videoBox.parent().removeClass("loading").find(".stream-loading").remove();
    					
    					//显示视频信息
    					self.videoBox.parent().find('.info').show();
    					//显示音频按钮
    					self.videoBox.parent().find('.audio').show();
    					self.videoBox.parent().find('.recv-audio-btn').attr("class", "unrecv-audio-btn");
    					self.videoBox.parent().find('.send-audio-btn').attr("class", "unsend-audio-btn");
    				}
    			});
    		},
    		
    		/**
    		 * 播放视频
    		 * video：视频编号（ID）
    		 */
    		play:function(video){
    			if(!video){
    				//alert("请输入视频ID");
    				promptAlarm('视频ID不能为空');
    				return;
    			}
    			var body = { 
    				request: "call",
    				videoidentify: video,
    				playseq:this.index,
    				userToken:userToken,
    				autoack:true
    			};
    			this.sipcall.send({"message": body });
    			this.video = video;
    			this.playing = true;
    			this.packetsLostRate = 0;
    			this.packetsLostSum = 0;
    			this.packetsReceivedSum = 0;
    			
    			//loading
    			var _li = this.videoBox.parent();
    			if(!_li.hasClass("loading")){
    				_li.addClass("loading").append('<div class="stream-loading">等待数据流传送...</div>');						
    			}	
    			console.log("视频播放：分屏=" + (this.index + 1) + ",设备ID=" + video);
    		},
    		
    		close:function(type){
    			var reqType = type ? type : "hangup";
    			if(!this.playing) return;
    			var _hangup = {
    				"request": reqType,
    				"videoidentify":this.video,
    				"playseq": this.index,
    				"token": userToken
    			};
    			this.sipcall.send({"message": _hangup});
    			this.sipcall.hangup();
    			this.videoBox.hide();
    			this.playing = false;
    			this.video = null;
    			this.packetsLostRate = 0;
    			this.packetsLostSum = 0;
    			this.packetsReceivedSum = 0;
    			//清除显示的视频信息
        		document.getElementById('info-' + (Number(this.index) + Number(1))).innerHTML = '';
        		//隐藏视频信息
        		this.videoBox.parent().find('.info').hide();
        		//隐藏音频喇叭
				this.videoBox.parent().find('.audio').hide();				
    			//避免没收到成功时就点击关闭，清除loading框
    			this.videoBox.parent().removeClass("loading").find(".stream-loading").remove();
    		},
    		
            /**
             * 云台控制
             * up  				上
             * down				下
             * left				左
             * right			右
             * upleft			上左
             * upright			上右
             * downleft			下左
             * downright		下右
             * zoomin			倍率变大
             * zoomout			倍率变下
             * focusnear		焦点+
             * focusfar			焦点-
             * irisopen			光圈+
             * irisclose		光圈-
             * pointset			设置预置点
             * pointdel			删除预置点
             * pointgoto		到预置点
             * scansetleft		自动扫描左边界
             * scansetright		自动扫描又边界
             * scansetspeed		设置扫描速度
             * scanrun			自动扫描运行
             * cruiseadd		添加巡航点
             * cruisedel		删除巡航点
             * cruisespeed		设置巡航点速度
             * cruisepausetime	设置巡航滞留时间
             * cruiserun		启动巡航
             */
            holder: function(type, opts, isStop) {
    			if(!this.video || !this.playing){
    				//alert("请输入视频ID");
    				promptAlarm('未选中播放的视频！');
    				return;
    			}
    			
            	var holdType = 'up down left right upleft upright downleft downright zoomin zoomout focusnear focusfar irisopen irisclose pointset pointdel pointgoto '+
				'scansetleft scansetright scansetspeed scanrun cruiseadd cruisedel cruisespeed cruisepausetime cruiserun';
            	var typeVal = (Number(holdType.split(' ').indexOf(type))+Number(1));
            	
            	console.log("holdType：" + typeVal + " type：" + type + (isStop ? ' 停止' : ''));

            	if (!typeVal || typeVal <= 0) {
            		console.error('异常PTZ指令：'  + typeVal);
            		return false;
            	}
              	
    			var body = { 
    				request: "ptz",
    				videoidentify: this.video,
    				playseq: this.index,
    				userToken: userToken,
        		};
    			
        		body.cmd = {
            		speed: opts.speed ? opts.speed : 200,
            		group: 0,
            		present: opts.present ? opts.present : 0,
            		time: 0,
            		type: typeVal
            	}
        		
            	if(isStop) {
            		console.log(">>>>yuntai control,stop, video=" + this.video);
            		body.cmd.action =  1;
            	} else {
            		body.cmd.action =  0;           	
                	console.log('设备号：'+this.video+', 云台移动-->'+ type);  
            	}
        		
    			this.sipcall.send({"message": body });
            },
            
            /**
             * 历史回放
             * video设备ID startTime录像开始 stopTime录像结束 例：2015-07-22T12:00:00，注意T隔开
             */
            playback: function(video, startTime, stopTime) {
    			if(!video){
    				//alert("请输入视频ID");
    				promptAlarm('视频ID不能为空');
    				return;
    			}
    			
    			var body = { 
    				request: "av_playback",
    				videoidentify: video,
    				playseq: this.index,
    				userToken:userToken,
    				start_time: startTime,
    				stop_time: stopTime
        		};
    			
    			console.log(">>>>playback video=" + video +" startTime=" + startTime + " stopTime=" + stopTime);
    			this.sipcall.send({"message": body });
    			this.video = video;
    			this.playing = true;
    			this.packetsLostRate = 0;
    			this.packetsLostSum = 0;
    			this.packetsReceivedSum = 0;
    			
    			//loading
    			var _li = this.videoBox.parent();
    			if(!_li.hasClass("loading")){
    				_li.addClass("loading").append('<div class="stream-loading">等待数据流传送...</div>');						
    			}	
    			console.log("历史回放：分屏=" + (this.index + 1) + ",视频ID=" + video);
            },
                  
            /**
             * 历史回放控制
             * video设备ID playType类型 playSpeed速率 startTime开始时间
             */
            playbackControl: function(video, playType, playSpeed, startTime) {
            	var self = this;
            	
    			var body = { 
    				request: "av_control",
    				videoidentify: video,
    				playseq: self.index,
    				userToken: userToken,
    				start_time: startTime,
    				rate: String(playSpeed),
    				cmd: playType
            	};
        		
    			console.log(">>>>playbackControl video=" + video + " playType=" + playType + " playSpeed=" + playSpeed);
    			
		        //setTimeout(function (){
    			self.sipcall.send({"message": body });
		        //}, 1000);
		        
		        if (playType == 'stop') {
		        	self.videoBox.hide();
		        	self.playing = false;
		        	self.video = null;
		        	self.packetsLostRate = 0;
		        	self.packetsLostSum = 0;
		        	self.packetsReceivedSum = 0;
	    			//清除显示的视频信息
	        		document.getElementById('info-' + (Number(self.index) + Number(1))).innerHTML = '';
	    			//避免没收到成功时就点击关闭，清除loading框
	        		self.videoBox.parent().removeClass("loading").find(".stream-loading").remove();
		        }
            },
            
            /**
             * 音频流操作
             * requstType: recv_audio、stop_audio、send_audio、unsend_audio
             */
            operateAudio: function(requestType) {
            	var self = this;
            	
    			if(!self.video){
    				//alert("请输入视频ID");
    				promptAlarm('视频ID不能为空');
    				return;
    			}
    			var body = { 
    				request: requestType,
    				videoidentify: self.video,
    				playseq: self.index,
    				userToken: userToken,
    			};
    			self.sipcall.send({"message": body });
	
    			console.log("音频操作="+ requestType +", 分屏=" + (self.index + 1) + ",设备ID=" + self.video);
            }
    }
    
    return isIE() ? VideoOcx : VideoWebRtc;
}));

















