
/**
 * video工具类
 * @author xiyongqiang
 * @version 1.4.3
 * @update 2019-12-13
 */

(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);
    }
}(window, 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;
    }

    /**
     * 公共方法
     * 提示
     */
    var showPrompt = true;
    function promptSuccess(msg, type) {
        console.log(msg);
        //panduanpromptView弹层对象是否引入
        'undefined' != typeof(promptView) && showPrompt && promptView.showSuccess(msg);
    }
    function promptFailed(msg, type) {
        console.error(msg);
        'undefined' != typeof(promptView) && showPrompt && promptView.showFailed(msg);
    }
    function promptAlarm(msg, type) {
        console.info(msg);
        'undefined' != typeof(promptView) && showPrompt && promptView.showAlarm(msg);
    }

    /**
     * 公共方法
     * 判断能否获取本地声卡设备
     */
    function checkUserMediaAvailable() {
        return Janus.isGetUserMediaAvailable() && !checkIsHttp() && window.hasAudioInputDevices;
    }

    /**
     * 公共方法
     * 是否有声卡设备
     * 异步方法  结果保存在window.hasAudioInputDevices中 true or false
     */
    function hasMediaDevices() {
        if (window.checkAudioDevicesStatus != undefined && window.hasAudioInputDevices != undefined) {
            //已检测
            return;
        }
        //参数初始化，防止为空报错
        window.checkAudioDevicesStatus = false;
        window.hasAudioInputDevices = false;
        if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
            console.log("Not support enumerateDevices() .");
            return;
        }
        var startTime = new Date().getTime();
        // 列出相机和麦克风.
        navigator.mediaDevices.enumerateDevices()
            .then(function(devices) {
                devices.forEach(function(device) {
                    if (device.kind == "audioinput") {
                        //判断到1个就返回true
                        window.hasAudioInputDevices = true;
                    }
                });
                window.checkAudioDevicesStatus = true;
                console.log("检查音频输入设备总计耗时: " + (new Date().getTime() - startTime) + "ms");
            })
            .catch(function(err) {
                console.log(err.name + ": " + err.message);
            });
    }

    /**
     * 公共方法
     * 判断是否是http 或者 https
     */
    function checkIsHttp() {
        var protocolStr = document.location.protocol;
        if(protocolStr == "http:" || window.location.hostname == "localhost" ) return true;
        return false;
    }

    /**
     * 公共方法
     * 判断是否是https 和检测http分开的目的是还有本地打开的情况(前缀为file:)
     * webrtc规定打开摄像头、麦克风需要加密传输  所以需要再https环境下， 本地打开不需要加密 可以正常获取
     * 这也是分开的另一个目的
     */
    function checkIsHttps() {
        var protocolStr = document.location.protocol;
        if(protocolStr == "https:") 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;

            if (waitTimerId) {
                clearTimeout(waitTimerId);
                waitTimerId = null;
            }
        };
        return PollTimer;
    }());


    var waitTimerId = 0;
    function wait(time) {
        return new Promise(function(resolve, reject) {
            if (waitTimerId) {
                clearTimeout(waitTimerId);
                waitTimerId = null;
            }
            waitTimerId = setTimeout(resolve, time);
        });
    }

    /**
     * 事件
     */
    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;
        },

        /**
         * 清空事件
         */
        removeAllListeners: function () {
            this._listeners = {};
        }
    }

    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 &&
                (this._getChoiceWindow() != -1 && !this.getInChoiceVideo())){
                return this.playInChoice(video,id,opts);
            }
            return this.play(freeWindow,video,id,opts);
        },

        /**
         * 扩展视频窗口数的播放方式
         */
        playByOrderExpandWindow: function(video,id,opts){

            var freeWindow = this._getMinIndexFreeWindow(0);

            var maxWindows = this._opts.windowsNum || 16;

            while (this._opts.windows < maxWindows && 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;
        },

        /**
         * 判断指定窗口是否正在播放视频
         */
        isPlayingByIndex: function(index){
            return this.videoStatus[index] && true;
        },

        /**
         * 获取视频数据
         */
        getVideoData: function(){
            return this.videoStatus;
        },

        /**
         * 关闭语音
         * @param index
         */
        closeVoice: function(index) {
            this._obj.SCWebVoiceComControl(this.videoStatus[index].video, this.videoStatus[index].playId, 0);
        },

        /**
         * 根据playId获取窗口
         * @param playId
         * IE下才有该方法
         */
        getWindowByPlayId: function(playId) {
            var index = -1;
            $.each(this.videoStatus,function(key,val){
                if (playId == val.playId) {
                    index = key;
                    return false;
                }
            });
            return index;
        },

        /**
         * 根据窗口获取playId
         * @param index
         * IE下才有该方法
         */
        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];
            }

        },

        /**
         * 关闭指定视频编号正在播放的视频
         */
        closeByVideo: function(video, isSave){
            var me = this;

            if (video == undefined) {
                console.info('video参数错误');
                return;
            }

            var videoData = me.videoStatus;
            if (!videoData || videoData.length == 0) {
                return;
            }

            for (var i in videoData) {
                if (video == videoData[i].video) {
                    me.close(videoData[i].index);
                }
            }
        },

        /**
         *
         */
        closeHistory: function(playId) {
            var close = this._obj.SCWebStopRealPlay(playId);
            console.log("close = "+close);
            var index = this._getChoiceWindow();
            delete this.videoStatus[index];
        },

        /**
         * 关闭所有视频
         * TODO 不可关闭
         */
        closeAll: function(isSave){
            var me = this;
            isSave || (this._disableClosed = []);
            var windows = me._obj.SCWebGetRealPlayWindows();
            console.log('要关闭的视频窗：' + windows);
            if (windows) {
                $.each(windows.split(','),function(i,index){
                    me.close(index,isSave);
                    console.log('窗口：' + i);
                });
            }
        },

        /**
         * 获取视频窗口
         * @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();

            //延迟
            me.delayTimeId = 0;

            me._polltimer = new PollTimer(function(firstRun){
                me.closeAll();

                if (me.delayTimeId) {
                    clearTimeout(me.delayTimeId);
                }

                me.delayTimeId = setTimeout(function() {
                    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);
                    }
                }, 1000)
            }, 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, 1, _opts.time);
            console.log('设备号：'+ video +', 云台移动-->'+ type);
        },

        /**
         * 视频回放
         * @param startTime [YYYY-MM-DDTHH:mm:ss]
         * @param endTime
         * @return playId
         */
        playHistory: function(video,startTime,endTime,opts) {
            var me = this;
            var playId = me._obj.SCWebHistoryPlay(video, startTime, endTime);
            console.log("play = " + playId);

            if (playId < 0) {
                var name = opts.name || '视频';
                promptFailed(name + '播放失败！');
                return playId;
            }

            var index = me._getChoiceWindow();

            opts = opts || {};
            playId > 0 && (me.videoStatus[index] = {
                video: video,
                id: video,
                playId: playId,
                opts: opts,
                isPlayBack: true
            }, me.dispatch('playsuccess', me.videoStatus[index]));

            return playId;
        },

        /**
         * 历史流控制
         * @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;
        },

        /**
         * 获取截屏数据
         */
        getScreenCaptureData: function(index, callback) {
            var msg = 'IE下暂不支持获取截屏数据！';
            console.log(msg)
            throw Error(msg);
        },

        /**
         * 添加事件
         */
        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);
        },

        /**
         * 获取ocx的版本信息
         */
        getOcxVersion: function() {
            return this._obj.SCWebDecoderGetVersion();
        },

        /*
       * 总的初始化
       * 参数示例：
       * 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._opts.showPrompt === false && (showPrompt = false);
            //事件注册区域
            me._addStopHandler();
            me._addClickHandler();
            me._addHisHandler();
            me._addCapPicHandler();
            me._addHistoryPlayHandler();

            //浏览器刷新/关闭前执行
            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);
            //是否开启抓图

            conf.ip == '127.0.0.1' && (conf.ip = location.hostname);

            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) {
                if (me.getWindowByPlayId(playId) != -1 &&
                    me.videoStatus[me.getWindowByPlayId(playId)].isPlayBack) {
                    me.closeHistory(playId);
                } else {
                    me.close(me.getWindowByPlayId(playId));
                }

                me.dispatch('streamoff', {playId:playId,videoId:videoId});
            };
            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);');
        },

        //监听截图事件
        _addCapPicHandler: function() {
            var me = this;
            window.getCapPicPath = function(playId, capPicPath, capPicName) {
                me.dispatch('getCapPicPath', {playId:playId, capPicPath:capPicPath, capPicName: capPicName});
            };
            me._regEvent('SCWebGetCapPicPathName(playId, capPicPath, capPicName)', 'getCapPicPath(playId, capPicPath, capPicName);');
        },

        //监听点击视频框的历史回放
        _addHistoryPlayHandler: function() {
            var me = this;
            window.historyPlay = function(playId, videoId) {
                me.dispatch('historyPlay', {playId:playId, videoId:videoId});
            };
            me._regEvent('SCWebHistoryPlayEvent(playId, videoId)', 'historyPlay(playId, videoId);');
        },

        _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){
        var _self = this;
        if (!opts) {
            console.error('VideoWebRtc的参数opts不能为空');
            return;
        }
        hasMediaDevices();

        //检测声卡设备为异步方法，耗时在几十毫秒左右，因此需要做延迟
        //默认检查次数为40  间隔为20ms
        var count = 0;
        var index = setInterval(function () {
            if (count == 40) {
                clearInterval(index);
                _self._init($dom,opts);
            } else {
                if (window.checkAudioDevicesStatus) {
                    clearInterval(index);
                    _self._init($dom,opts);
                }
            }
            count++;
        }, 20);
    }

    /**
     * 使用WEB-RTC方式的视频播放的方法
     */
    VideoWebRtc.prototype = {
        constructor: VideoWebRtc,

        VIDEO_DATA: [], //记录视频各分屏的状态

        /**
         * 播放视频
         * 参数：index(视频窗口编号，从0开始) video(视频设备id，即devId) id(标识，空的话使用设备id) opts(其他参数)
         * opts.businessType  0:调度业务  1：勤指
         * 返回true/false
         */
        play: function(index, video, id, opts){
            var me = this;
//        	if (me.isPlaying(id) != -1) {
//        		console.info('该视频正在播放');
//        		return false;
//        	}
            // 启用播放队列时，当前位置正在关闭上一个视频，则加入播放队列
            if (me.waitPlayQueueSwitch && me.VIDEO_DATA[index].isClosing) {
                me._addWaitingVideo(index, video, id, opts);
                return ;
            }
            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 &&
                (this._getChoiceWindow() != -1 && !this.getInChoiceVideo() && this._opts.windowsNum > 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);
//        	}

            var maxWindows = this._opts.windowsNum || 16;

            while (me._opts.windows < maxWindows && 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){
                var index = selView.attr("index");
                if (me.VIDEO_DATA[index].playing) {
                    me.close(index);
                    //延时打开  禁止同时一关一开
                    setTimeout(function(){
                        me.play(index, video, id, opts);
                    }, 1000);
                } else {
                    me.play(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;
        },

        /**
         * 判断指定窗口是否正在播放视频
         */
        isPlayingByIndex: function(index){
            var me = this;
            if (index > me.VIDEO_DATA.length - 1 || index < 0) return false;

            return me.VIDEO_DATA[index].playing;
        },

        /**
         * 获取视频数据
         */
        getVideoData: function(){
            return this.VIDEO_DATA;
        },

        /**
         * 关闭指定窗口的视频
         */
        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]);
            }

        },

        /**
         * 关闭指定视频编号正在播放的视频
         */
        closeByVideo: function(video, isSave){
            var me = this;

            if (video == undefined) {
                console.info('video参数错误');
                return;
            }

            var videoData = me.VIDEO_DATA;
            if (!videoData || videoData.length == 0) {
                return;
            }

            for (var i in videoData) {
                if (video == videoData[i].video) {
                    me.close(videoData[i].index);

                    if (!isSave) {
                        me.dispatch('afterclose', videoData[i]);
                    }
                }
            }
        },

        /**
         * 关闭所有视频
         */
        closeAll: function(isSave){
            var me = this;
            // 清除所有等待播放队列
            me._removeAllWaitingVideo();
            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)
                }*/
                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, flag:me._opts.flag});
        },

        /**
         * 询问是否无可用窗口
         */
        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();

                if (firstRun) {
                    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++;
                    }
                    me.dispatch('startpoll', array);
                } else {
                    wait(1500).then(function(){
                        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++;
                        }
                    })
                }
            }, 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.setChoiceWindow(index);
            me.VIDEO_DATA[index].opts = opts;
            return me.VIDEO_DATA[index].playback(video,startTime,endTime);
        },

        /**
         * 关闭历史流
         */
        closeHistory: function(video, index) {
            if (!video) return;

            var me = this;

            if (!index) {
                var index;
                if (me._opts.windowsNum == 1) {
                    index = me._opts.windowsBeginIndex;
                }
            }

            return me.VIDEO_DATA[index].playbackControl(video, "stop", 0);
        },

        /**
         * 历史流控制
         * @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.attr("index")].video){
                return me.VIDEO_DATA[selView.attr("index")];
            }
            return undefined;
        },

        /**
         * 设置全屏
         */
        setFullScreen: function() {
            this._fullScreenEvent(document.getElementById("video-main-web-rtc"));
        },

        /**
         * 获取当前视频控件的配置项
         */
        getVideoControllerOpts: function() {
            return this._opts;
        },

        /**
         * 获取截屏数据
         * @param callback 回调函数
         */
        getScreenCaptureData: function(index, callback) {
            var me = this;

            //如果index为空则使用选中窗口的index
            var dataObj = me.VIDEO_DATA[index != undefined  ? index : me._getChoiceWindow()];

            if (!dataObj.playing) {
                promptAlarm('请选择播放的视频源！');
                return;
            }

            var canvasObj = document.getElementById('myCanvas');
            var videoObj = dataObj.tagBox.get(0);

            if (videoObj == undefined) {
                return;
            }
            // 取流中 取视频框尺寸
            // 播放中 取视频画面尺寸
            if (dataObj.tagBox.parent().find(".stream-loading").length != 0) {
                canvasObj.width = dataObj.tagBox.width();
                canvasObj.height = dataObj.tagBox.height();
            } else {
                canvasObj.width = videoObj.videoWidth;
                canvasObj.height = videoObj.videoHeight;
            }

            var ctx = canvasObj.getContext("2d");
            ctx.drawImage(videoObj, 0, 0, videoObj.videoWidth, videoObj.videoHeight);

            var dataUrl = canvasObj.toDataURL('image/jpeg');
            callback ? callback(dataUrl) : null;
        },

        /**
         * 开始录像
         */
        startAvRecord: function(index) {
            var me = this;
            return me.VIDEO_DATA[index].recordAv("start_av_record", recordAvBusinessId);
        },

        /**
         * 结束录像
         */
        stopAvRecord: function(index) {
            var me = this;
            return me.VIDEO_DATA[index].recordAv("stop_av_record", recordAvBusinessId);
        },

        /**
         * 改变分辨率
         * @param resolution 新分辨率
         */
        changeResolution: function(index, resolution) {
            var me = this;
            return me.VIDEO_DATA[index].changeResolution("change_resolution", resolution);
        },

        /**
         * 开启对讲预呼叫
         * @param pocNo 对讲号码
         * @param centerTel 调度中心号
         */
        openPocCall: function(pocNo, centerTel) {
            var me = this;

            var index;
            //对讲预呼叫默认使用一个窗口
            if (me._opts.windowsNum == 1) {
                index = me._opts.windowsBeginIndex;
            } else {
                index = me._getMinIndexFreeWindow();
            }

            if (index < 0) {
                console.error('窗口编号获取失败！')
            }

            //保存对讲号码
            window.pocNo = pocNo;
            return me.VIDEO_DATA[index].pocCall("open_poccall", pocNo, centerTel);
        },

        /**
         * 关闭对讲预呼叫
         * @param pocNo 对讲号码
         * @param centerTel 调度中心号
         */
        closePocCall: function(pocNo, centerTel) {
            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].stream = null;
            window.pocNo = null;
            return me.VIDEO_DATA[index].pocCall("close_poccall", pocNo, centerTel);
        },

        /**
         * 设置录像的businessId
         * @param businessId 业务ID
         */
        setRecordAvBusinessId: function(businessId) {
            //var me = this;
            recordAvBusinessId = businessId;
        },

        /**
         * 开启音频
         */
        sendAudio: function(index) {
            var me = this;
            var index = (index != undefined ? index : me._opts.windowsBeginIndex);
            me.VIDEO_DATA[index].stream.getAudioTracks()[0].enabled = true;
        },

        /**
         * 关闭音频
         */
        unSendAudio: function(index) {
            var me = this;
            var index = (index != undefined ? index : me._opts.windowsBeginIndex);
            me.VIDEO_DATA[index].stream.getAudioTracks()[0].enabled = false;
        },

        /**
         * 添加事件
         */
        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);
        },

        /**
         * 清空事件
         */
        removeAllListeners: function() {
            videoListener.removeAllListeners();
        },

        /**
         * 获取编号最小的空闲窗口的编号， 正在播放或有视频在等待播放标识不是空闲窗口
         */
        _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 && !me.VIDEO_DATA[index].isWaiting) {
                    return index;
                }
            }
            return -1;
        },

        /**
         * 获取选中的窗口的index
         */
        _getChoiceWindow: function() {
            var me = this;
            var selView = $('[video-flag="' + me._opts.windowsBeginIndex+'"]>li.sel');
            if (selView.length) {
                return selView.attr("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)];
                }
            }
        },

        /**
         * 设置鼠标选中窗口
         */
        _initWindowEvent: 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 src = null;
            $('[video-flag="'+me._opts.windowsBeginIndex+'"]>li').bind("dragstart", function (ev) {
                src = $(this);
            })

            $('[video-flag="'+me._opts.windowsBeginIndex+'"]>li').bind("dragover", function (ev) {
                ev.preventDefault();
            })

            $('[video-flag="'+me._opts.windowsBeginIndex+'"]>li').bind("drop", function (ev) {
                ev.preventDefault();
                if(src.prop("outerHTML") === $(this).prop("outerHTML")){
                    return;
                }
                var target = $(this);
                var srcIndex = src.index();
                var targetIndex = target.index();

                if (srcIndex > targetIndex) {
                    src.insertBefore(target);
                    target.insertAfter($('.video-main li').eq(srcIndex));
                } else {
                    src.insertAfter(target);
                    target.insertBefore($('.video-main li').eq(srcIndex));
                }
            })
        },

        /*
       * 总的初始化
       * 参数示例：
       * 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,
                isVideoTag: true,  //true生成video标签 false生产audio标签 默认true
                showVideoInfo: 1, //显示分辨率、码率等信息，1-显示左下角 2-显示左上角，为0时控制_showVideoInfo函数处理，默认1
                waitPlayQueueSwitch: false, //播放队列开关，默认false
                defaultBusinessType: 0, // 配置的默认业务类型  0：调度主线  1：勤指
                videoTipTimeOut: 5, // 超时无首屏检测时间
            };

            $.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;
            // 对讲号码初始化
            window.pocNo = 0;
            // 播放队列开关 默认打开
            me.waitPlayQueueSwitch = opts.waitPlayQueueSwitch == undefined ? false : opts.waitPlayQueueSwitch;

            //是否提示
            me._opts.showPrompt === false && (showPrompt = false);
            // 勤指业务下 设备检测
            me._opts.defaultBusinessType == 1 && me._checkDevices();
            //初始化界面
            me._opts.isVideoTag ? me._initVideoView($dom, me._opts.showVideoInfo) : me._initAudioView($dom);
            //初始化Janus
            me._initJanus();
            //初始化按钮点击事件
            me._initBtnEvent();
            // 初始化事件监听
            me._initEventListen();
            //设置鼠标点击选中窗口
            me._initWindowEvent();
            if (me._opts.showVideoInfo != 0) {
                //显示视频信息：名称、分辨率、码率、丢包率
                me._showVideoInfo();
            }
            //双击某个视频全屏
            me._dbClickFullScreen();
        },

        /**
         * 初始化按钮点击事件
         */
        _initBtnEvent: function() {
            var me = this;
            var videoFlagObj = $('[video-flag="'+me._opts.windowsBeginIndex+'"]');

            //锁定视频事件
            videoFlagObj.find("button[name='lockVideo']").click(function(){
                var index = Number($(this).parent().parent().attr("index"));

                if (!me.VIDEO_DATA[index].playing) {
                    promptAlarm('请选择播放的视频源！');
                    return;
                }

                if ($(this).attr('class') == 'lock-video-btn') {
                    me.VIDEO_DATA[index].isLockVideo = false;
                    $(this).attr('class', 'unlock-video-btn');
                } else {
                    me.VIDEO_DATA[index].isLockVideo = true;
                    $(this).attr('class', 'lock-video-btn');
                }
            });

            //接收音频事件
            videoFlagObj.find("button[name='recvAudio']").click(function(){
                var _self = this;
                var index = Number($(this).parent().parent().attr("index"));
                // 优先当前窗口参数设置的业务类型  其次配置的默认业务类型
                var businessType = me.VIDEO_DATA[index].opts.businessType == undefined ? me._opts.defaultBusinessType : me.VIDEO_DATA[index].opts.businessType;

                if (!me.VIDEO_DATA[index].playing) {
                    promptAlarm('请选择播放的视频源！');
                    return;
                }

                if ($(this).attr('class') == 'recv-audio-btn') {
                    //发送停止播放音频的请求
                    me.VIDEO_DATA[index].operateAudio("stop_audio")
                    $(this).attr('class', 'unrecv-audio-btn');
                    me.VIDEO_DATA[index].tagBox.prop("muted", true);
                } else {
                    if (businessType == 0) {
                        //发送前先关闭其它音频通道(包括接收和发送音频)
                        var lis = $($(_self).parent().parent().parent()).children();
                        for (var i = 0; i < lis.length; i++) {
                            var btnIndex = Number($(lis[i]).attr("index"));
                            if (index == btnIndex) {
                                continue;
                            }
                            var recvBtn = $($(lis[i]).find("button[name='recvAudio']")[0]);
                            var sendBtn = $($(lis[i]).find("button[name='sendAudio']")[0]);

                            if (recvBtn.attr("class") == 'recv-audio-btn') {
                                if (me.VIDEO_DATA[btnIndex].playing) {
                                    recvBtn.click();
                                }
                            }
                            if (sendBtn.attr("class") == 'send-audio-btn') {
                                if (me.VIDEO_DATA[btnIndex].playing) {
                                    sendBtn.click();
                                }
                            }
                        }
                        //发送播放音频的请求
                        $(_self).attr('class', 'recv-audio-btn');
                        setTimeout(function () {
                            me.VIDEO_DATA[index].operateAudio("recv_audio");
                            me.VIDEO_DATA[index].tagBox.prop("muted", false);
                        }, 1000);
                    } else if (businessType == 1) {
                        // poc新模式支持回传多个音频，因此不关闭
                        //发送播放音频的请求
                        $(_self).attr('class', 'recv-audio-btn');
                        me.VIDEO_DATA[index].operateAudio("recv_audio");
                        me.VIDEO_DATA[index].tagBox.prop("muted", false)
                    }
                }
            });

            //发送音频事件
            videoFlagObj.find("button[name='sendAudio']").click(function(){
                var index = Number($(this).parent().parent().attr("index"));
                // 优先当前窗口参数设置的业务类型  其次配置的默认业务类型 最后默认调度业务
                var businessType = me.VIDEO_DATA[index].opts.businessType == undefined ? me._opts.defaultBusinessType : me.VIDEO_DATA[index].opts.businessType;

                if (!me.VIDEO_DATA[index].playing) {
                    promptAlarm('请选择播放的视频源！');
                    return;
                }

                if (businessType == 0) {
                    // 主线业务
                    if ($(this).attr('class') == 'send-audio-btn') {
                        me.VIDEO_DATA[index].operateAudio("unsend_audio")
                        $(this).attr('class', 'unsend-audio-btn');
                        me.VIDEO_DATA[index].stream.getAudioTracks()[0].enabled = false;
                    } else {
                        me.VIDEO_DATA[index].operateAudio("send_audio");
                        $(this).attr('class', 'send-audio-btn');
                        //	$(this).parent().find("button[name='recvAudio']").attr('class', 'recv-audio-btn')
                        me.VIDEO_DATA[index].stream.getAudioTracks()[0].enabled = true;
                    }
                } else if (businessType == 1) {
                    // 勤指业务
                    if ($(this).attr('class') == 'send-audio-btn') {
                        $(this).attr('class', 'unsend-audio-btn');
                        //关闭点对点对讲
                        me.VIDEO_DATA[index].ptopPoc("close_ptop_poc", window.pocNo);
                    } else {
                        $(this).attr('class', 'send-audio-btn');
                        //发起点对点对讲
                        me.VIDEO_DATA[index].ptopPoc("open_ptop_poc", window.pocNo);
                    }
                }
            });

            //关闭视频事件
            videoFlagObj.find("button[name='closeVideo']").click(function(){
                var index = Number($(this).parent().parent().attr("index"));
                me.close(index);
            });
        },

        /**
         * 初始化事件监听
         */
        _initEventListen: function () {
            var _self = this;
            // 打开视频 {index, video, id, opts} index(视频窗口编号，从0开始) video(视频设备id，即devId) id(标识，空的话使用设备id) opts(其他参数)
            _self.addListener('openVideo', function (e) {
                _self.play(e.index, e.video, e.id, e.opts);
            })

            // janus通知后台已关闭视频
            _self.addListener('notifyCloseVideo', function (e) {
                _self._notifyWaitingVideo(e.index);
            });
        },

        /**
         * 双击某个视频全屏
         */
        _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);

                        if (!videoObj) continue;

                        var width = videoObj.videoWidth;
                        var height = videoObj.videoHeight;

                        //码率
                        var bitrate = me.VIDEO_DATA[i].sipcall.getBitrate();
                        if (!width || !height || !bitrate || bitrate.indexOf("kbits") == -1 || bitrate.indexOf("NaN") != -1) {
                            continue;
                        }

                        var config = me.VIDEO_DATA[i].sipcall.webrtcStuff;
                        me._setPacketsLostRate(i, config, me);
                        var resolution = width + "×" + height;
                        switch(height + '') {
                            case '1080':
                                resolution = "1080P";
                                break;
                            case '720':
                                resolution = "720P";
                                break;
                            case '480':
                                resolution = "480P";
                                break;
                            case '288':
                                resolution = "CIF";
                                break;
                            default:
                                break;
                        }

                        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;' + resolution +
                            '<br>丢包率：' + me.VIDEO_DATA[i].packetsLostRate + '&nbsp;&nbsp;' + bitrate.replace("kbits/sec", "kbps");
                    }
                }
            }

            //已存在则清除
            if (me.videoInfoTimer) {
                clearInterval(me.videoInfoTimer);
                me.videoInfoTimer = null;
            }

            me.videoInfoTimer = 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' || res.packetsLost == 'NaN') {
                                    me.VIDEO_DATA[index].packetsLostRate = '0.00%';
                                } else {
                                    var packetsLost = Number(res.packetsLost) - Number(me.VIDEO_DATA[index].packetsLostSum);
                                    var packetsReceived = Number(res.packetsReceived) - Number(me.VIDEO_DATA[index].packetsReceivedSum);

                                    var packetsLostRate = 0;
                                    //防止分母是0
                                    if (packetsLost > 0) {
                                        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;*/
                            }
                        }

                    });
                });
            }
        },

        /**
         * 设备可用性检查（扬声器、麦克风、分辨率、浏览器类型）
         * 1. 未检测（status == undefined）询问进入检测界面
         * 2. 检测完成按相应结果给予相应提示
         * 3. 拒绝检测按所有检测通过处理
         * 4. 程序自行检测，并将是否加载声卡结果放入window对象
         * @private
         */
        _checkDevices: function() {
            var tipCountKey = "DEVICES_CHECK_TIP_COUNT";
            var statusKey = "DEVICES_CHECK_STATUS";
            var checkCompleted = "completed";
            var checkRejected = "rejected";
            var microResultKey = "MICRO_RESULT";
            var speakerResultKey = "SPEAKER_RESULT";
            var screenResultKey = "SCREEN_RESULT";
            var resultPass = "pass";
            var resultNotPass = "not pass";

            var tipCount = sessionStorage.getItem(tipCountKey);
            var status = localStorage.getItem(statusKey);
            if ((tipCount == undefined || tipCount == "0") && status == undefined) {
                sessionStorage.setItem(tipCountKey, "1");
                //弹窗讯问是否进入检测界面
                if (confirm("您还没有检测硬件设备，是否先进行检测？")) {
                    window.open("/scooper-video/new/checkDevices");
                } else {
                    localStorage.setItem(statusKey, checkRejected);
                }
                return;
            }

            if (status == checkCompleted) {
                var microResult = (localStorage.getItem(microResultKey) == undefined) ? resultPass : localStorage.getItem(microResultKey);
                var speakerResult = (localStorage.getItem(speakerResultKey) == undefined) ? resultPass : localStorage.getItem(speakerResultKey);
                var screenResult = (localStorage.getItem(screenResultKey) == undefined) ? resultPass : localStorage.getItem(screenResultKey);

                var msg = "";
                if (microResult == resultNotPass || speakerResult == resultNotPass) {
                    msg += "您的声卡异常！";
                }
                if (screenResult === resultNotPass) {
                    msg += "您的屏幕分辨率过低，可能导致页面布局混乱！";
                    //提示并派发消息
                }
                var userAgent = navigator.userAgent;
                if (userAgent.toLowerCase().indexOf("chrome") < 0 &&  userAgent.toLowerCase().indexOf("firefox") < 0 && userAgent.toLowerCase().indexOf("edge") < 0) {
                    msg += "当前浏览器下部分功能可能存在兼容问题，建议使用谷歌浏览器！";
                }

                if (msg != "") {
                    //提示并派发消息
                    promptAlarm(msg);
                    //防止外部未监听消息就派发事件
                    setTimeout(function () {
                        videoListener.dispatch('msginfo', {'msg' : msg});
                    }, 3000);
                }
            }
        },

        /**
         * 视频界面的初始化，在传过来的dom中创建界面
         * @param infoPosition 视频码率等信息显示位置，1-显示左下角 2-显示左上角，为0时控制_showVideoInfo函数处理，默认左下角
         */
        _initVideoView: function($dom, infoPosition) {
            var me = this;
            var position;
            switch (infoPosition) {
                case 1: position = "info-bottom"; break;
                case 2: position = "info-top"; break;
                default : position = "info-bottom";
            }
            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) +'" draggable="true"><video muted class="video-box" id="video-' + i +'" autoplay ></video>' +
                    '<div class="hide info ' + position + '" id="info-' + i +'"></div>' +
                    '<div class="operate-btn">';
                videoHtml +='<button type="button" class="unlock-video-btn hide" name="lockVideo"></button>';
                checkUserMediaAvailable() && (videoHtml += '<button type="button" class="unsend-audio-btn hide" name="sendAudio"></button>');
                videoHtml += '<button type="button" class="unrecv-audio-btn hide" name="recvAudio"></button>' +
                    '<button type="button" class="close-btn hide" name="closeVideo"></button>' +
                    '</div>' +
                    '</li>';
            }
            videoHtml += '</ul> <div class="canvasBox hide"><canvas id="myCanvas" ></canvas></div>';
            $dom.append(videoHtml);

            me.setWindowsNum(me._opts.windows);
        },

        /**
         * 音频界面的初始化，在传过来的dom中创建界面
         */
        _initAudioView: 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 += '<audio id="audio-' + i +'" autoplay ></audio>';
            }
            $dom.append(videoHtml);
        },

        /**
         * 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 janusUrl = me._opts.conf.janusUrl;
                    checkIsHttps() && (janusUrl = janusUrl.replace('ws:','wss:'));
                    janusUrl.indexOf("127.0.0.1") > 0 && (janusUrl = janusUrl.replace('127.0.0.1', location.hostname));
                    me._opts.janus = new Janus({
                        //如果是https 则用页面的url头（已保证用nginx代理为前提） 否则用后台配置的
                        server: location.protocol == "https:" ? janusUrl.split("//")[0] + "//" + (location.host) + "/janus/" : janusUrl,
                        success: function(){
                            console.log("Janus服务连接成功！");
                            me._initSVideo(me._opts.janus);
                        },
                        error: function(error) {
                            //只提示一次，防止Janus挂了一直重连
                            !me._opts.isNotFistTip && promptFailed('Janus服务连接失败！');
                            me._opts.isNotFistTip = true;

                            console.error('Janus服务连接失败：'+ error)
                            me.closeAll();
                            me._removeAllWaitingVideo();
                            me._initJanus();
                        },
                        destroyed: function() {
                            me._opts.isNotFistTip = true;
                        }
                    });

                }});
        },

        /**
         * 销毁：Janus销毁、资源释放
         */
        destoryJanus: function() {
            var me = this;
            me._opts.janus.destroy({
                success: function() {
                    window.windowsSum = 0;
                    //userToken = null;
                    registered = false;
                },
                asyncRequest: true,
                notifyDestroyed: true,

            });
            me.removeAllListeners();
        },

        reLoginJanusItvIndex : -1,
        /**
         * 初始化插件、登陆，初始化窗口
         */
        _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: me._opts.conf.janusPlugin ? me._opts.conf.janusPlugin : "janus.plugin.videoserver",
                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) {
                    promptFailed('Janus登陆插件初始化失败！');
                    console.error("Janus登陆插件初始化失败：" + error);
                },
                onmessage: function(msg, jsep) {
                    if (msg.error_code) {
                        console.error(msg.error)
                        promptFailed(CONST_CODE.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(CONST_CODE.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"]);
                            if(me.reLoginJanusItvIndex == -1) {
                                me.reLoginJanusItvIndex = setInterval(function () {
                                    console.log("尝试重新登陆janus！");
                                    me._initJanus(janus);
                                }, 5000);
                            }
                            return;
                        }
                        if (event === 'video_server_closed') {
                            if(me.reLoginJanusItvIndex == -1) {
                                me.reLoginJanusItvIndex = setInterval(function () {
                                    console.log("尝试重新登陆janus！");
                                    me._initJanus(janus);
                                }, 5000);
                            }
                            return;
                        }
                        if(event === 'registered') {
                            var userToken = result["userToken"];
                            console.log('janus登陆成功')
                            registered = true;
                            if (me.reLoginJanusItvIndex != -1) {
                                clearInterval(me.reLoginJanusItvIndex);
                                me.reLoginJanusItvIndex = -1;
                            }

                            //生成主界面
                            //相对序号，用于标识当前janus连接初始化的序号窗口
                            var relativeIndex = 0;
                            for(var i = me._opts.windowsBeginIndex; i < me._opts.windowsBeginIndex + me._opts.windowsNum; i++){
                                me.VIDEO_DATA[i] = new SVideo({
                                    index: i,
                                    userToken: userToken,
                                    janus: janus,
                                    windowsNum: me._opts.windowsNum,
                                    relativeIndex: relativeIndex++,
                                    flag: me._opts.flag,
                                    isVideoTag: me._opts.isVideoTag,
                                    janusPlugin: me._opts.conf.janusPlugin,
                                    videoTipTimeOut: me._opts.videoTipTimeOut
                                });
                            }
                        }
                    }
                }
            });
        },

        /* ----------------------------- 播放队列 --------------------------- */

        // 记录等待中的视频
        WAITING_DATA: [],

        // 播放队列开关 默认关闭
        waitPlayQueueSwitch: false,

        /**
         * 添加等待视频数据
         * 同一位置再次打开，则覆盖上一次的
         * 参数：index(视频窗口编号，从0开始) video(视频设备id，即devId) id(标识，空的话使用设备id) opts(其他参数)
         */
        _addWaitingVideo: function (index, video, id, opts) {
            var _self = this;
            var isOverride = false;
            $.each(_self.WAITING_DATA, function (i, obj) {
                if (obj.index == index) {
                    console.log("播放队列中 index = " + index + ", video = " + obj.video + " 替换为 video = " + video);
                    _self.WAITING_DATA[i] = {
                        index: index,
                        video: video,
                        id: id,
                        opts: opts
                    }
                    isOverride = true;
                    return false;
                }
            });
            if (!isOverride) {
                _self.WAITING_DATA.push({
                    index: index,
                    video: video,
                    id: id,
                    opts: opts
                });
                console.log("index = " + index + ", video = " + video + " 加入播放队列");
            }
            _self.VIDEO_DATA[index].isWaiting = true;
        },

        /**
         * 删除等待视频数据
         */
        _removeWaitingVideo: function (index, video) {
            var _self = this;
            $.each(_self.WAITING_DATA, function (i, obj) {
                if (obj.index == index && obj.video == video) {
                    _self.WAITING_DATA.splice(i, 1);
                    _self.VIDEO_DATA[index].isWaiting = false;
                    console.log("index = " + index + ", video = " + video + " 从播放队列移除");
                    return false;
                }
            });
        },

        /**
         * 删除所有等待播放视频的数据
         */
        _removeAllWaitingVideo: function () {
            var _self = this;
            _self.WAITING_DATA = [];
            var index = _self._opts.windowsBeginIndex;
            for (; index < _self._opts.windowsBeginIndex + _self._opts.windows ; index++) {
                _self.VIDEO_DATA[index].isWaiting = false;
            }
        },

        /**
         * 上一个视频关闭后，如果该位置由等待视频，通知打开新视频
         * @param index
         */
        _notifyWaitingVideo: function (index) {
            var _self = this;
            $.each(_self.WAITING_DATA, function (i, obj) {
                if (obj.index == index) {
                    _self.play(obj.index, obj.video, obj.id, obj.opts);
                    _self._removeWaitingVideo(obj.index, obj.video);
                    return false;
                }
            });
        }

    }

    var CONST_CODE = {
        VIDEO_CODE: {
            2002 : "打开失败，未找到该ID的视频源",
            2003 : "打开失败，请确认视频服务版本",
            3001 : "打开失败，未接收到引流包，请检查端口映射",
            3002 : "",
            3003 : "打开失败，对方拒绝视频请求",
            4001 : "打开失败，视频流中断",
            4002 : "终端挂机或超时未接听",
            7000 : "打开失败，无法连接视频设备",
            7001 : "打开失败，无法连接视频设备",
            7002 : "打开失败，无法连接视频设备",
        },

        OTHER_CODE: {
            453 : "videoServer连接失败，错误码453",
            454 : "视频窗口已被占用，请选择其它窗口打开或停止播放",
            455 : "操作失败，该段时间无视频录像",
            499 : "操作异常，错误码499",
            440 : "操作异常，错误码440",
            441 : "操作异常，错误码441",
            442 : "操作异常，错误码442",
            443 : "操作异常，错误码443",
            444 : "操作异常，错误码444",
            445 : "操作异常，错误码445",
            446 : "操作异常，错误码446",
            447 : "操作异常，错误码447",
            448 : "操作异常，错误码448",
            449 : "操作异常，错误码449",
            450 : "操作异常，错误码450",
            451 : "操作异常，错误码451",
            452 : "操作异常，错误码452",
            456 : "设备已处于对讲状态或不支持对讲",
            6001 : "录像失败"
        },

        FAILED_CODE: {
            1001 : "账号或密码错误",
            1002 : "该帐号已连接",
            1004 : "没有鉴权",
            2001 : "未携带token或token错误",
            2002 : "视频源id不存在",
            2003 : "操作指令非法(该账号不允许执行这个指令，或者不支持该指令)",
            3001 : "nat通道未建立",
            3002 : "该视频流已在传输",
            3003 : "无法获取远端视频流",
            4001 : "视频流异常断开连接",
            4002 : "获取视频失败",
            5000 : "内部错误",
            8001 : "该设备不支持云台操作",
            453  : "videoServer连接失败",
            454  : "录像回放窗口已占用，请先停止播放",
            455  : "无视频录像，操作失败",
            5001 : "呼叫异常断开",
            5002 : "禁止修改分辨率",
            401  : "禁止修改分辨率",
            4003 : "音频重置",
            4004 : "音频被占用",
            4005 : "客户端已打开对讲",
            4006 : "终端离开云眼音频",
            6001 : "录像失败",
            499 : "内部创建失败",
            440 : "请求消息内容为空",
            441 : "json格式错误",
            442 : "无效的请求",
            443 : "消息内容缺失",
            444 : "消息缺少参数",
            445 : "账户已登陆",
            446 : "收到的videoserver消息有误",
            447 : "消息参数错误",
            448 : "SDP创建失败",
            449 : "未使用",
            450 : "创建端口失败",
            451 : "SDP创建失败",
            452 : "未使用加密的RTP",
            456 : "对讲未打开",
            7000 : "URL账号密码错误（RTSP）",
            7001 : "URL地址不通（RTSP）",
            7002 : "URL格式错误（RTSP）"
        },

        /**
         * 以下的错误状态不会关闭视频
         */
        STATUS_CODE_ARR: ['5002', '401', '4003', '4004', '4005', '4006', '8001', '6001']
    }

    /**
     * 显示播放错误内容, 4002特殊处理
     * @param videoObj 视频对象
     * @param code 状态码（包含错误码）
     * @param isShowReplayBtn 是否显示重新播放按钮
     * @param video 打开错误的视频Id
     */
    function showResult(videoObj, code, isShowReplayBtn, video) {
        var videoDom = videoObj.tagBox.parent();

        videoDom.addClass("result");
        videoDom.find('.operate-btn .close-btn').show();

        if (CONST_CODE.FAILED_CODE[code] && code != "4002") {
            var resultHtml = "<div class='real-result'>错误码" + code + ": " + CONST_CODE.FAILED_CODE[code] + "</div>"
            videoDom.append(resultHtml);
        }

        var resultHtml = "<div class='result'><div class='result-tip'>" + CONST_CODE.VIDEO_CODE[code] + "</div>";
        if(isShowReplayBtn && code != "4002") {
            resultHtml += "<div class='result-replay'><span id='replay-" + videoObj.index + "' class='replay'>点击重试</span></div>"
        }
        resultHtml += "</div>";
        videoDom.append(resultHtml);
        if(isShowReplayBtn && code != "4002") {
            $("#replay-" + videoObj.index).unbind("click").click(function () {
                videoListener.dispatch("openVideo", {index: videoObj.index, video: video, id: videoObj.id, opts: videoObj.opts});
            });
        }
        if (code == "4002") {
            setTimeout(function () {
                clearResult(videoDom);
            }, 5000);
        }
    }

    /**
     * 清除显示内容  videoDom: 视频Dom对象
     */
    function clearResult(videoDom, videoObj) {
        videoDom.removeClass("result");
        videoDom.find(".real-result").remove();
        videoDom.find(".result").remove();
        if (!videoObj.playing) {
            // bug id 18654: 增加是否正在播放判断
            videoDom.find('.operate-btn .close-btn').hide();
        }
    }

    //window.VIDEO_DATA = [];//记录视频各分屏的状态
    window.windowsSum = 0; //当前页面的视频总数，可能有多个VideoWebRtc对象
    //var userToken = null;
    var registered = false;
    var recordAvBusinessId = null;

    function SVideo (opts) {
        this.janus = opts.janus;
        this.userToken = opts.userToken;
        this.sipcall = null;
        this.index = opts.index;
        this.relativeIndex = opts.relativeIndex;
        this.tagBox = opts.isVideoTag ? $('#video-' + (this.index + 1)) : $('#audio-' + (this.index + 1));
        this.windowsNum = opts.windowsNum;
        this.flag = opts.flag;
        this.isVideoTag = opts.isVideoTag;
        this.janusPlugin = opts.janusPlugin;
        this.isClosing = false; // 当前分屏是否正在关闭视频
        this.isWaiting = false; // 当前分屏是否有视频在等待播放
        this.playSucTimeOutIndex = -1; // 超时提示定时器index
        this.videoTipTimeOut = opts.videoTipTimeOut; // 超时无首屏时间
        this.init();
    }

    /**
     * 使用web-rtc方式的视频播放
     */
    SVideo.prototype = {

        /**
         * 初始化
         */
        init:function(){
            var self = this;

            self.janus.attach({
                plugin: self.janusPlugin ? self.janusPlugin : "janus.plugin.videoserver",
                opaqueId:"siptest-" + Janus.randomString(12),

                success: function(pluginHandle) {
                    console.log("视频插件初始化成功:" + self.index);
                    self.sipcall = pluginHandle;

                    if (self.relativeIndex + 1 >= self.windowsNum) {
                        videoListener.dispatch('initsucc', self);
                    }
                },

                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("请先登陆");
                    }

                    var video = self.video;
                    if (msg.error_code) {
                        console.error("错误码：" + msg.error_code + " " + CONST_CODE.FAILED_CODE[msg.error_code]);
                        if (CONST_CODE.VIDEO_CODE[msg.error_code]) {
                            showResult(self, msg.error_code, true, video);
                        } else {
                            promptFailed(CONST_CODE.OTHER_CODE[msg.error_code] || CONST_CODE.FAILED_CODE[msg.error_code] || '错误码：' + msg.error_code);
                        }
                        videoListener.dispatch('msginfo', {'code': msg.error_code, 'msg' : CONST_CODE.OTHER_CODE[msg.error_code] || CONST_CODE.FAILED_CODE[msg.error_code] || '错误码：' + msg.error_code});
                        return false;
                    }

                    var result = msg["result"];
                    if (!result) return;
                    if (result.error_code && result.error_code != 0) {
                        console.error("错误码：" + result.error_code + " " + CONST_CODE.FAILED_CODE[result.error_code]);
                        if (!CONST_CODE.STATUS_CODE_ARR.includes(result.error_code + '')) {
                            //播放失败 关闭视频
                            self.close('err');
                            if (self.isLockVideo) {
                                setTimeout(function () {
                                    self.play(video);
                                }, 1500);
                            } else {
                                videoListener.dispatch('afterclose', self);
                            }
                        }

                        videoListener.dispatch('msginfo', {'code': result.error_code, 'msg' : CONST_CODE.OTHER_CODE[result.error_code] || CONST_CODE.FAILED_CODE[result.error_code] || '错误码：' + result.error_code});
                        if (CONST_CODE.VIDEO_CODE[result.error_code]) {
                            showResult(self, result.error_code, true, video);
                        } else {
                            promptFailed(CONST_CODE.OTHER_CODE[result.error_code] || CONST_CODE.FAILED_CODE[result.error_code] || '错误码：' + result.error_code);
                        }
                        self.tagBox.parent().find('.recv-audio-btn').attr("class", "unrecv-audio-btn");
                        self.tagBox.parent().find('.send-audio-btn').attr("class", "unsend-audio-btn");
                    }

                    //事件响应
                    var event = result["event"];
                    if (!event) return;
                    switch(event) {
                        //即将播放视频
                        case 'incomingcall':
                            self.sipcall.createAnswer({
                                jsep: jsep,
                                media: { audioSend: checkUserMediaAvailable(), videoSend:false, audioRecv: true, videoRecv: true},
                                success: function(jsep) {
                                    var body = {
                                        request:"accept",
                                        videoidentify: result["videoidentify"],
                                        playseq: parseInt(result["playseq"]),
                                        userToken: self.userToken,
                                    };
                                    self.sipcall.send({"message": body, "jsep": jsep});
                                },
                                error: function(error) {
                                    console.error(error);
                                }
                            });
                            break;
                        case 'accepted' :
                            self.playSucTimeOutIndex = setTimeout(function () {
                                var _li = self.tagBox.parent();
                                _li.append('<div class="video-tip">网络环境较差，可能无法正常加载视频</div>');
                            }, self.videoTipTimeOut * 1000);
                            break;
                        //呼叫失败
                        case 'callfaild':
                            //promptFailed(FAILED_CODE[result.error_code] || '错误码：' + result.error_code);
                            break;
                        //云台
                        case 'ptz':
                            break;
                        //历史流控制
                        case 'av_control':
                            break;
                        //录像通知
                        case 'start_av_record':
                            if (result && result.filename) {
                                self.videoFileName = result.filename;
                                videoListener.dispatch('startRecordVideo', self);
                                console.log('录像地址：' + result.filename);
                            }
                            break;
                        case 'stop_av_record':
                            if (result && result.filename) {
                                self.videoFileName = result.filename;
                                videoListener.dispatch('stopRecordVideo', self);
                                console.log('录像地址：' + result.filename);
                            }
                            break;
                        //修改分辨率
                        case 'ser_notify_resolution':
                            if (result && result.resolution) {
                                self.resolution = result.resolution;
                                videoListener.dispatch('notifyresolution', self);
                                console.log('接收notifyresolution：' + result.resolution);
                                //promptAlarm('当前分辨率：' + result.resolution);
                            }
                            break;
                        //建立预呼叫响应
                        case 'open_poccall':
                            console.log('建立预呼叫');
                            self.sipcall.createAnswer({
                                jsep: jsep,
                                media: {audioSend: checkUserMediaAvailable(), videoSend:false, audioRecv: true , videoRecv: false},
                                success: function(jsep) {
                                    var body = {
                                        request:"accept",
                                        userToken:  self.userToken,
                                    };
                                    self.sipcall.send({"message": body, "jsep": jsep});
                                },
                                error: function(error) {
                                    console.error(error);
                                    promptFailed("发生未知错误，请重试或联系管理员!");
                                    videoListener.dispatch('msginfo', {'msg' : "发生未知错误，请重试或联系管理员!"});
                                }
                            });
                            break
                        //预呼叫异常断开
                        case 'ser_close_poccall':
                            console.log('预呼叫异常断开');
                            break;
                        case 'ser_stop_audio':
                            self.tagBox.parent().find('.recv-audio-btn').attr("class", "unrecv-audio-btn");
                            console.log('音频异常关闭！');
                            break;
                        case 'close_down_audio':
                            self.tagBox.parent().find('.send-audio-btn').attr("class", "unsend-audio-btn");
                            promptSuccess("通话时间到");
                            console.log('通话时间到！');
                            break;
                        case 'ser_notify_dispatch_close_ptop_poc':
                            self.tagBox.parent().find('.send-audio-btn').attr("class", "unsend-audio-btn");
                            console.log('调度通知点对点对讲关闭！');
                            break;
                        case 'ser_close_ptop_poc':
                            self.tagBox.parent().find('.send-audio-btn').attr("class", "unsend-audio-btn");
                            console.log('点对点对讲关闭！');
                            break;
                        case 'ser_open_ptop_poc':
                            self.tagBox.parent().find('.unsend-audio-btn').attr("class", "send-audio-btn");
                            console.log('点对点对讲打开！');
                            break;
                        // 视频关闭通知
                        case 'ser_close_video':
                            console.log('视频框 ' + self.index + ' 视频已关闭');
                            self.isClosing = false;
                            videoListener.dispatch('notifyCloseVideo', self);
                            break;
                        default:
                            console.log('event：' + event);
                            break;
                    }
                },

                //处理远程流
                onremotestream: function(stream) {
                    console.log('onremotestream：分屏=' + (self.index + 1) + ', video='  + self.video);
                    Janus.attachMediaStream(self.tagBox.get(0), stream);
                },

                //处理本地流
                onlocalstream: function(stream) {
                    stream.getAudioTracks()[0].enabled = false;
                    self.stream = stream;
                },

                //清理

                oncleanup: function() {
                    console.log('oncleanup：分屏=' + (self.index + 1));
                }
            });

            //<video>注册playing/canplay事件，用于判断视频播放成功
            self.tagBox.bind("canplay play playing", function () {
                if(self.video){
                    if (self.tagBox.is(':visible')) return;

                    // 清除播放监测定时任务，清除内容
                    self.playSucTimeOutIndex > 0 && clearTimeout(self.playSucTimeOutIndex);
                    self.tagBox.parent().find(".video-tip").remove();

                    console.log('分屏=' + (self.index + 1) + ', ' + self.video + ' 播放成功');
                    promptSuccess('分屏' + (self.index + 1) + ' 播放成功');
                    self.tagBox.show();
                    //self.tagBox.parent().removeClass("loading").find(".stream-loading").remove();
                    self.tagBox.parent().find(".stream-loading").remove();

                    //显示视频信息
                    self.tagBox.parent().find('.info').show();

                    //显示音频按钮
                    self.tagBox.parent().find('.operate-btn button').show();
                    if (self.isPlayBack) {
                        self.tagBox.parent().find('.unrecv-audio-btn').hide();
                    }
                    self.tagBox.parent().find('.recv-audio-btn').attr("class", "unrecv-audio-btn");
                    self.tagBox.parent().find('.send-audio-btn').attr("class", "unsend-audio-btn");

                    var width = this.videoWidth;
                    var height = this.videoHeight;
                    //保持长宽比例填充video视频框
                    if (width <= height && width != '0') {
                        self.tagBox.css('object-fit', 'contain');
                    }
                }
            });
        },

        /**
         * 播放视频
         * video：视频编号（ID）
         */
        play:function(video){
            if(!video){
                //alert("请输入视频ID");
                promptAlarm('视频ID不能为空');
                return;
            }
            var body = {
                request: "call",
                videoidentify: video,
                playseq: this.index,
                userToken: this.userToken,
                autoack: true
            };
            this.sipcall.send({"message": body });
            this.video = video;
            this.playing = true;
            this.packetsLostRate = '0.00%';
            this.packetsLostSum = 0;
            this.packetsReceivedSum = 0;

            //loading
            var _li = this.tagBox.parent();
            clearResult(_li, this);
            if(!_li.hasClass("loading")){
                _li.addClass("loading").append('<div class="stream-loading">等待数据流传送...</div>');
            }
            _li.find('.operate-btn .close-btn').show();
            console.log("视频播放：分屏=" + (this.index + 1) + ",设备ID=" + video);
        },

        close:function(type){
            if (!type) {
                this.isLockVideo = false;
                this.tagBox.parent().find('.lock-video-btn').attr("class", "unlock-video-btn");
            }
            //清除结果提示内容
            clearResult(this.tagBox.parent(), this);

            //var reqType = type ? type : "hangup";
            if(!this.playing) return;
            var _hangup = {
                request: "hangup",
                videoidentify: this.video,
                playseq: this.index,
                userToken: this.userToken
            };
            this.sipcall.send({"message": _hangup});
            this.sipcall.hangup();
            this.tagBox.hide();
            this.isClosing = true;
            this.playing = false;
            this.video = null;
            this.packetsLostRate = '0.00%';
            this.packetsLostSum = 0;
            this.packetsReceivedSum = 0;
            //清除显示的视频信息
            document.getElementById('info-' + (Number(this.index) + Number(1))).innerHTML = '';
            //隐藏视频信息
            this.tagBox.parent().find('.info').hide();
            //隐藏音频喇叭
            this.tagBox.parent().find('.operate-btn button').hide();
            //避免没收到成功时就点击关闭，清除loading框
            this.tagBox.parent().removeClass("loading").find(".stream-loading").remove();
            //清除object-fit
            this.tagBox.css('object-fit', '');
            // 清除内容提示
            this.playSucTimeOutIndex > 0 && clearTimeout(this.playSucTimeOutIndex);
            this.tagBox.parent().find(".video-tip").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){
                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: this.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){
                promptAlarm('视频ID不能为空');
                return;
            }

            var body = {
                request: "av_playback",
                videoidentify: video,
                playseq: this.index,
                userToken: this.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.00%';
            this.packetsLostSum = 0;
            this.packetsReceivedSum = 0;
            this.isPlayBack = true;

            //loading
            var _li = this.tagBox.parent();
            clearResult(_li, this);
            if(!_li.hasClass("loading")){
                _li.addClass("loading").append('<div class="stream-loading">等待数据流传送...</div>');
            }
            _li.find('.operate-btn .close-btn').show();
            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: self.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.close();

                self.tagBox.hide();
                self.playing = false;
                self.video = null;
                self.packetsLostRate = '0.00%';
                self.packetsLostSum = 0;
                self.packetsReceivedSum = 0;
                self.isPlayBack = false;
                //清除显示的视频信息
                document.getElementById('info-' + (Number(self.index) + Number(1))).innerHTML = '';

                //隐藏音频喇叭
                this.tagBox.parent().find('.operate-btn button').hide();
                //避免没收到成功时就点击关闭，清除loading框
                self.tagBox.parent().removeClass("loading").find(".stream-loading").remove();
                //清除object-fit
                self.tagBox.css('object-fit', '');
            }
        },

        /**
         * 音频流操作
         * requstType: recv_audio、stop_audio、send_audio、unsend_audio
         */
        operateAudio: function(requestType) {
            var self = this;

            if(!self.video){
                promptAlarm('视频ID不能为空');
                return;
            }
            var body = {
                request: requestType,
                videoidentify: self.video,
                playseq: self.index,
                userToken: self.userToken,
            };

            self.sipcall.send({"message": body });
            console.log("音频操作="+ requestType +", 分屏=" + (self.index + 1) + ",设备ID=" + self.video);
        },

        /**
         * 录像操作
         * requstType: start_av_record(开启录像)、stop_av_record(停止录像)
         */
        recordAv: function(requestType, businessId) {
            var self = this;

            if(!self.video){
                promptAlarm('视频ID不能为空');
                return;
            }
            var body = {
                request: requestType,
                videoidentify: self.video,
                playseq: self.index,
                userToken: self.userToken,
                businessid: businessId || null
            };

            self.sipcall.send({"message": body });
            console.log("录像操作="+ requestType +", 分屏=" + (self.index + 1) + ",设备ID=" + self.video + ",业务ID=" + (businessId || null));
        },

        /**
         * 修改分辨率
         * requstType: change_resolution
         * CIF 480P 720P 1080P
         */
        changeResolution: function(requestType, resolution) {
            var self = this;

            if(!self.video){
                promptAlarm('视频ID不能为空');
                return;
            }

            var body = {
                request: requestType,
                videoidentify: self.video,
                playseq: self.index,
                resolution: resolution,
                userToken: self.userToken,
            };

            self.sipcall.send({"message": body });
            console.log("修改分辨率操作="+ resolution +", 分屏=" + (self.index + 1) + ",设备ID=" + self.video);
        },

        /**
         * 对象预呼叫
         * requstType: open_poccall(开启) close_poccall(关闭)
         * pocno
         * centerTel
         */
        pocCall: function(requestType, pocNo, centerTel) {
            var self = this;

            var body = {
                request: requestType,
                pocno: pocNo,
                playseq: self.index,
                center_tel: centerTel,
                userToken: self.userToken,
            };

            self.sipcall.send({"message": body });
            console.log("预呼叫操作="+ requestType +", 对讲号码=" + pocNo + ",调度中心号码=" + centerTel);
        },

        /**
         * 点对点对讲
         * requstType: open_ptop_poc(开启) close_poc_poc(关闭)
         * pocno
         */
        ptopPoc: function(requestType, pocNo) {
            var self = this;

            var body = {
                request: requestType,
                pocno: pocNo,
                playseq: self.index,
                pocmember: self.video,
                userToken: self.userToken,
            };

            self.sipcall.send({"message": body });
            console.log("点对点对讲操作="+ requestType +", 主叫号码=" + pocNo + ",被叫号码=" + self.video);
        }
    }

    return isIE() ? VideoOcx : VideoWebRtc;
}));

















