/**

 * jssdk 2.4

 */

(function (global, factory) {



  "use strict";



  if (typeof module === "object" && typeof module.exports === "object") {

    module.exports = global.document ?

      factory(global, true) :

      function (w) {

        if (!w.document) {

          throw new Error("EZUIPlayer requires a window with a document");

        }

        return factory(w);

      };

  } else {

    factory(global);

  }



  // Pass this if window is not defined yet

})(typeof window !== "undefined" ? window : this, function (window, noGlobal) {



  /**

   * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed

   */

  !function (a, b) { function c(a, b) { var c = a.createElement("p"), d = a.getElementsByTagName("head")[0] || a.documentElement; return c.innerHTML = "x<style>" + b + "</style>", d.insertBefore(c.lastChild, d.firstChild) } function d() { var a = t.elements; return "string" == typeof a ? a.split(" ") : a } function e(a, b) { var c = t.elements; "string" != typeof c && (c = c.join(" ")), "string" != typeof a && (a = a.join(" ")), t.elements = c + " " + a, j(b) } function f(a) { var b = s[a[q]]; return b || (b = {}, r++ , a[q] = r, s[r] = b), b } function g(a, c, d) { if (c || (c = b), l) return c.createElement(a); d || (d = f(c)); var e; return e = d.cache[a] ? d.cache[a].cloneNode() : p.test(a) ? (d.cache[a] = d.createElem(a)).cloneNode() : d.createElem(a), !e.canHaveChildren || o.test(a) || e.tagUrn ? e : d.frag.appendChild(e) } function h(a, c) { if (a || (a = b), l) return a.createDocumentFragment(); c = c || f(a); for (var e = c.frag.cloneNode(), g = 0, h = d(), i = h.length; i > g; g++)e.createElement(h[g]); return e } function i(a, b) { b.cache || (b.cache = {}, b.createElem = a.createElement, b.createFrag = a.createDocumentFragment, b.frag = b.createFrag()), a.createElement = function (c) { return t.shivMethods ? g(c, a, b) : b.createElem(c) }, a.createDocumentFragment = Function("h,f", "return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&(" + d().join().replace(/[\w\-:]+/g, function (a) { return b.createElem(a), b.frag.createElement(a), 'c("' + a + '")' }) + ");return n}")(t, b.frag) } function j(a) { a || (a = b); var d = f(a); return !t.shivCSS || k || d.hasCSS || (d.hasCSS = !!c(a, "article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")), l || i(a, d), a } var k, l, m = "3.7.3", n = a.html5 || {}, o = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i, p = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i, q = "_html5shiv", r = 0, s = {}; !function () { try { var a = b.createElement("a"); a.innerHTML = "<xyz></xyz>", k = "hidden" in a, l = 1 == a.childNodes.length || function () { b.createElement("a"); var a = b.createDocumentFragment(); return "undefined" == typeof a.cloneNode || "undefined" == typeof a.createDocumentFragment || "undefined" == typeof a.createElement }() } catch (c) { k = !0, l = !0 } }(); var t = { elements: n.elements || "abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video", version: m, shivCSS: n.shivCSS !== !1, supportsUnknownElements: l, shivMethods: n.shivMethods !== !1, type: "default", shivDocument: j, createElement: g, createDocumentFragment: h, addElements: e }; a.html5 = t, j(b), "object" == typeof module && module.exports && (module.exports = t) }("undefined" != typeof window ? window : this, document);



  /*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */

  if ("document" in self) { if (!("classList" in document.createElement("_"))) { (function (j) { "use strict"; if (!("Element" in j)) { return } var a = "classList", f = "prototype", m = j.Element[f], b = Object, k = String[f].trim || function () { return this.replace(/^\s+|\s+$/g, "") }, c = Array[f].indexOf || function (q) { var p = 0, o = this.length; for (; p < o; p++) { if (p in this && this[p] === q) { return p } } return -1 }, n = function (o, p) { this.name = o; this.code = DOMException[o]; this.message = p }, g = function (p, o) { if (o === "") { throw new n("SYNTAX_ERR", "An invalid or illegal string was specified") } if (/\s/.test(o)) { throw new n("INVALID_CHARACTER_ERR", "String contains an invalid character") } return c.call(p, o) }, d = function (s) { var r = k.call(s.getAttribute("class") || ""), q = r ? r.split(/\s+/) : [], p = 0, o = q.length; for (; p < o; p++) { this.push(q[p]) } this._updateClassName = function () { s.setAttribute("class", this.toString()) } }, e = d[f] = [], i = function () { return new d(this) }; n[f] = Error[f]; e.item = function (o) { return this[o] || null }; e.contains = function (o) { o += ""; return g(this, o) !== -1 }; e.add = function () { var s = arguments, r = 0, p = s.length, q, o = false; do { q = s[r] + ""; if (g(this, q) === -1) { this.push(q); o = true } } while (++r < p); if (o) { this._updateClassName() } }; e.remove = function () { var t = arguments, s = 0, p = t.length, r, o = false, q; do { r = t[s] + ""; q = g(this, r); while (q !== -1) { this.splice(q, 1); o = true; q = g(this, r) } } while (++s < p); if (o) { this._updateClassName() } }; e.toggle = function (p, q) { p += ""; var o = this.contains(p), r = o ? q !== true && "remove" : q !== false && "add"; if (r) { this[r](p) } if (q === true || q === false) { return q } else { return !o } }; e.toString = function () { return this.join(" ") }; if (b.defineProperty) { var l = { get: i, enumerable: true, configurable: true }; try { b.defineProperty(m, a, l) } catch (h) { if (h.number === -2146823252) { l.enumerable = false; b.defineProperty(m, a, l) } } } else { if (b[f].__defineGetter__) { m.__defineGetter__(a, i) } } }(self)) } else { (function () { var b = document.createElement("_"); b.classList.add("c1", "c2"); if (!b.classList.contains("c2")) { var c = function (e) { var d = DOMTokenList.prototype[e]; DOMTokenList.prototype[e] = function (h) { var g, f = arguments.length; for (g = 0; g < f; g++) { h = arguments[g]; d.call(this, h) } } }; c("add"); c("remove") } b.classList.toggle("c3", false); if (b.classList.contains("c3")) { var a = DOMTokenList.prototype.toggle; DOMTokenList.prototype.toggle = function (d, e) { if (1 in arguments && !this.contains(d) === !e) { return e } else { return a.call(this, d) } } } b = null }()) } };





  Date.prototype.Format = function (fmt) { //author: meizz

    var o = {

      "M+": this.getMonth() + 1, //月份

      "d+": this.getDate(), //日

      "h+": this.getHours(), //小时

      "m+": this.getMinutes(), //分

      "s+": this.getSeconds(), //秒

      "q+": Math.floor((this.getMonth() + 3) / 3), //季度

      "S": this.getMilliseconds() //毫秒

    };

    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));

    for (var k in o)

      if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));

    return fmt;

  };





  // var Domain = 'https://open.ys7.com';

  // var logDomain = 'https://log.ys7.com/statistics.do';



  // var jqueryJS = Domain + '/sdk/js/2.0/js/jquery.min.js';

  // var ckplayerJS = Domain + '/sdk/js/2.0/js/ckplayer/ckplayer.js';

  // var ckplayerSWF = Domain + '/sdk/js/2.0/js/ckplayer/ckplayer.swf';

  // var m3u8SWF = Domain + '/sdk/js/2.0/js/ckplayer/m3u8.swf';

  // var flv_js = Domain + '/sdk/js/2.0/js/flv.min.js';

  // var hlsJS = Domain + '/sdk/js/2.0/js/hls.min.js';

  // var mpegJS = Domain + '/sdk/js/2.0/js/jsmpeg.min.js';

  // var wav = Domain + '/sdk/js/2.0/js/wav-audio-encoder.js';



    var Domain = '../static/EZUIKit1/js';

  var logDomain = 'https://log.ys7.com/statistics.do';



  var jqueryJS = Domain + '/jquery.min.js';

  var ckplayerJS = Domain + '/ckplayer/ckplayer.js';

  var ckplayerSWF = Domain + '/ckplayer/ckplayer.swf';

  var m3u8SWF = Domain + '/ckplayer/m3u8.swf';

  var flv_js = Domain + '/flv.min.js';

  var hlsJS = Domain + '/hls.min.js';

  var mpegJS = Domain + '/jsmpeg.min.js';

  var wav = Domain + '/wav-audio-encoder.js';





  // 当前页面是否是https协议

  var isHttps = window.location.protocol === 'https:' ? true : false;

  // 是否为移动端

  var isMobile = !!navigator.userAgent.match(/(iPhone|iPod|iPad|Android|ios|SymbianOS)/i);

  var testVideo = document.createElement('video');

  // 是否支持video标签和addEventListener方法（主要为了区别ie8）

  var isModernBrowser = !!testVideo.canPlayType && !!window.addEventListener;

  // 是否能使用video原生播放hls，目前只有safari可以支持原生video播放。

  var isNativeSupportHls = isModernBrowser && testVideo.canPlayType('application/vnd.apple.mpegURL');

  // 是否能使用hls.js播放

  var isSupportHls = false;

  // 是否使用flash

  var useFlash = false;



  // 本地信息上报

  var LOCALINFO = 'open_netstream_localinfo';

  // 预览主表上报

  var PLAY_MAIN = 'open_netstream_play_main';



  function dclog(obj) {

    var domain = window.location.protocol + '//' + window.location.host;

    var logObj = {

      Ver: 'v.2.3.0',

      PlatAddr: domain,

      ExterVer: 'Ez.2.3.0',

      CltType: 102,

      StartTime: (new Date()).Format('yyyy-MM-dd hh:mm:ss.S'),  // 每个日志包含当前的时间

      OS: navigator.platform

    }

    for (var i in obj) {

      logObj[i] = obj[i];

    }



    var tempArray = [];

    for (var j in logObj) {

      tempArray.push(j + '=' + logObj[j]);

    }

    var params = '?' + tempArray.join('&');

    // 上报一次本地统计信息

    var img = new Image();

    img.src = logDomain + params;

  }



  // 上报一次本地信息

  dclog({

    systemName: LOCALINFO

  });



  var RTMP_REG = /^rtmp/;

  var HLS_REG = /\.m3u8/;



  // 获取元素样式

  function getStyle(el) {

    return window.getComputedStyle

      ? window.getComputedStyle(el, null)

      : el.currentStyle;

  }



  // 加载js

  function addJs(filepath, callback) {

    var oJs = document.createElement("script");

    oJs.setAttribute("src", filepath);

    oJs.onload = callback;

    document.getElementsByTagName("head")[0].appendChild(oJs);

  }

  // 通用请求方法

  function request(url, method, params, header, success, error) {

    var _url = url;

    var http_request = new XMLHttpRequest();

    http_request.onreadystatechange = function () {

      if (http_request.readyState == 4) {

        if (http_request.status == 200) {

          var _data = JSON.parse(http_request.responseText);

          success(_data);

        }

      }

    };

    http_request.open(method, _url, true);

    // http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

    var data = new FormData();

    for (i in params) {

      data.append(i, params[i]);

    }

    http_request.send(data);

  };

  //获取url参数

  function getQueryString(name, url) {

    var r = new RegExp("(\\?|#|&)" + name + "=(.*?)(#|&|$)");

    var m = (url || location.href).match(r);

    return decodeURIComponent(m ? m[2] : '');

  }

  /**判断是否为promise对象 */

  function isPromise(obj) { return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'; }





  var EZUIPlayer = function (playParams) {

    if (!isModernBrowser) {

      throw new Error('不支持ie8等低版本浏览器');

      return;

    }

    /**定义播放配置项 */

    this.opt = {};

    this.opt.sources = [];

    this.handlers = {};



    // 修订 - 支持JS Decoder 允许非字符串配置项

    if (typeof playParams === 'object' && playParams.decoderPath) {

      /* 校验播放器配置参数合法性 */

      // 解码器路径

      if (typeof playParams.decoderPath !== 'string' || typeof playParams.decoderPath === 'undefined') {

        throw new Error('EZUIDecoder requires the path of decoder');

        return;

      }

      // Id

      if (typeof playParams.id !== 'string' || typeof playParams.id === 'undefined') {

        throw new Error('EZUIDecoder requires parameter id');

        return;

      }

      if (typeof playParams.url !== 'string' || typeof playParams.url === 'undefined') {

        throw new Error('EZUIDecoder requires parameter url');

        return;

      }

      // 将播放地址配置在实例 opt 属性中

      this.opt.sources.push(playParams.url);

      // JSDecoder  只有一个播放地址

      this.opt.currentSource = this.opt.sources[0];



      /* 获取解码器用户配置项 - 开始 */

      /**

       * 调试模式配置

       * 可通过dev属性指定API服务域名

       */

      var domain = "https://open.ys7.com";

      if (playParams.env) {

        var environmentParams = playParams.env;

        domain = environmentParams.domain;

      }



      /** 创建jSPlugin 对象 */

      this.jSPlugin = {};

      var _this = this;

      /** 根据播放参数获取真实播放地址 */

      var getRealUrl = this.getRealUrl(playParams);

      /**是否自动播放 */

      if (isPromise(getRealUrl)) {

        getRealUrl.then(function () {

          var initDecoder = _this.initDecoder(playParams);

          if (isPromise(initDecoder) && (playParams.autoplay !== false)) {

            initDecoder.then(function () {

              _this.play({ handleError: playParams.handleError });

            })

          }

        })

        .catch(function(err){

          var initDecoder = _this.initDecoder(playParams);

          if (isPromise(initDecoder) && (playParams.autoplay !== false)) {

            initDecoder.then(function () {

             // _this.play({ handleError: playParams.handleError });

            })

          }

        });

      }

    } else {

      var elementID = '';

      if (typeof playParams === 'string') {         //缩写模式 new EZUIPlayer('myplayer')

        elementID = playParams;

      } else if (typeof playParams === 'object') {  //标准模式 new EZUIPlayer({id: 'myplayer'})

        elementID = playParams.id;

      }

      this.videoId = elementID;

      this.video = document.getElementById(elementID);

      if (!this.video) {

        throw new Error('EZUIPlayer requires parameter videoId');

      }

      var sources = this.video.getElementsByTagName('source');

      // 转为数组对象，不受removeChild影响

      sources = Array.prototype.slice.call(sources, 0);



      if (this.video.src) {

        // 移动端删除rtmp地址

        if (isMobile && RTMP_REG.test(this.video.src)) {

          this.video.removeAttribute('src');

          this.video.load();

        } else {

          this.opt.sources.push(this.video.src);

        }

      }



      var l = sources.length;

      if (l > 0) {

        for (var i = 0; i < l; i++) {

          // 移动端删除rtmp地址

          if (isMobile && RTMP_REG.test(sources[i].src)) {

            this.video.removeChild(sources[i]);

          } else {

            this.opt.sources.push(sources[i].src);

          }

        }

      }

      if (this.opt.sources.length < 1) {

        throw new Error('no source found in video tag.');

      }

      this.opt.cur = 0;

      this.opt.poster = this.video.poster;

      var videoStyle = getStyle(this.video);

      var width = this.video.width;

      var height = this.video.height;

      if (width) {

        this.opt.width = width;

        if (height) {

          this.opt.height = height;

        } else {

          this.opt.height = 'auto';

        }

        this.log('video width:' + this.opt.width + ' height:' + this.opt.height);

      } else {

        this.opt.width = videoStyle.width;

        this.opt.height = videoStyle.height;

        this.log('videoStyle.width:' + videoStyle.width + ' wideoStyle.height:' + videoStyle.height);

      }

      this.opt.parentId = elementID;

      this.opt.autoplay = this.video.autoplay ? true : false;

      this.log('autoplay:' + this.video.autoplay);



      this.opt.currentSource = this.opt.sources[this.opt.cur];

      this.getRealUrl(playParams);

    }



    /* 创建播放，错误，停止事件钩子，上报用户行为 */

    this.handlers = {};

    this.initTime = (new Date()).getTime();



    this.on('play', function () {

      // 上报播放成功信息

      dclog({

        systemName: PLAY_MAIN,

        playurl: this.opt.currentSource,

        Time: (new Date()).Format('yyyy-MM-dd hh:mm:ss.S'),

        Enc: 0,  // 0 不加密 1 加密

        PlTp: 1,  // 1 直播 2 回放

        Via: 2,  // 2 服务端取流

        ErrCd: 0,

        Cost: (new Date()).getTime() - this.initTime  // 毫秒数

      });

    });

    this.retry = 2;

    this.on('error', function () {

      dclog({

        systemName: PLAY_MAIN,

        playurl: this.opt.currentSource,

        cost: -1,

        ErrCd: -1

      });

    });

  };



  // 事件监听

  EZUIPlayer.prototype.on = function (eventName, callback) {

    if (typeof eventName !== 'string' || typeof callback !== 'function') {

      return;

    }

    if (typeof this.handlers[eventName] === 'undefined') {

      this.handlers[eventName] = [];

    }

    this.handlers[eventName].push(callback);

  };



  // 事件触发

  EZUIPlayer.prototype.emit = function () {

    if (this.handlers[arguments[0]] instanceof Array) {

      var handlers = this.handlers[arguments[0]];

      var l = handlers.length;

      for (var i = 0; i < l; i++) {

        handlers[i].apply(this, Array.prototype.slice.call(arguments, 1));

      }

    }

  };



  EZUIPlayer.prototype.getRealUrl = function (playParams) {

    var _this = this;

    var apiDomain = 'https://open.ys7.com';

    if (playParams && playParams.env) {

      apiDomain = playParams.env.domain;

    }

    /** jsDecoder 获取真实地址 -- 开始 */

    if (playParams && playParams.decoderPath) {

      var getRealUrlPromise = function (resolve, reject, ezopenURL) {

        var realUrl = '';

        if (!/^ezopen:\/\//.test(ezopenURL)) { // JSDecoder ws协议播放

          resolve(ezopenURL);

        } else {

          var nodeUrl = apiDomain + "/jssdk/ezopen/getStreamToken?accessToken=" + playParams.accessToken + '&num=10&type=' + (playParams.url.indexOf('live') !== -1 ? 'live' : 'playback');

          var nodeSuccess = function (data) {

            if (data.retcode === 0) {

              realUrl = realUrl + data.data.params + '&ssn=' + data.data.tokens[0];

              // _this.opt.currentSource = realUrl;

              resolve(realUrl);

            } else {

              resolve('get realURL error')

              throw new Error('获取播放token失败');

            }

          }

          var nodeError = function (error) {

            console.log("getdecoder url from api error", error);

            throw new Error('获取播放token失败');

          }

          // 向API请求真实地址

          var apiUrl = apiDomain + "/api/lapp/live/url/ezopen";

          var apiSuccess = function (data) {

            if (data.code == 200 || data.retcode == 0) {

              // 处理验证码

              var validateCode = getQueryString('checkCode',data.data);

              //var validateCode = 'ZQGWMV';

              if(validateCode){

                _this.opt.validateCode = validateCode;

              }

              realUrl += data.data;

              /**参数容错处理  start*/

              if (data.data.indexOf('playback') !== -1) { //回放

                // 兼容各种时间格式

                if (!getQueryString('begin', data.data)) {

                  var defaultDate = new Date();

                  realUrl = realUrl + '&begin=' + defaultDate.Format('yyyyMMdd') + 'T000000Z';

                } else {

                  realUrl = realUrl.replace('&begin=' + getQueryString('begin', data.data), '&begin=' + formatRecTime(getQueryString('begin', data.data), '000000'))

                }

                if (!getQueryString('end', data.data)) {

                  var defaultDate = new Date();

                  realUrl = realUrl + '&end=' + defaultDate.Format('yyyyMMdd') + 'T235959Z';

                } else {

                  realUrl = realUrl.replace('&end=' + getQueryString('end', data.data), '&end=' + formatRecTime(getQueryString('end', data.data), '235959'))

                }

                // api错误处理

                if (!getQueryString('stream', data.data)) {

                  realUrl = realUrl.replace('stream', '&stream');

                }

              }

              request(nodeUrl, 'GET', '', '', nodeSuccess, nodeError);

            } else {

              resolve('get realURL error')

              //throw new Error('获取播放设备信息失败');

            }

            /**参数容错处理  end*/

          }

          var apiError = function (error) {

            console.log("getdecoder url from api error", error);

            resolve('get realURL error')

            //throw new Error('获取播放设备信息失败');

          }

          var isHttp = 'false';

          if (playParams && playParams.env && playParams.env.domain) {

            isHttp = playParams.env.domain.indexOf('https') !== -1 ? 'false' : 'true';

          } else {

            isHttp = window.location.href.indexOf('https') !== -1 ? 'false' : 'true';

          }

          var apiParams = {

            ezopen: ezopenURL,

            userAgent: window.navigator.userAgent,

            isFlv: false,

            addressTypes: null,

            isHttp: isHttp,

            accessToken: playParams.accessToken,

          }

          request(apiUrl, 'POST', apiParams, '', apiSuccess, apiError);

        }

      }

      var urlList = playParams.url.split(',')

      var promiseTaskList = [];

      var promiseTaskFun = (ezopenURL) => {

        return new Promise((resolve, reject) => getRealUrlPromise(resolve, reject, ezopenURL))

      };

      urlList.map(function (item, index) {

        promiseTaskList.push(promiseTaskFun(item));

      });

      var getRealUrlPromiseObj = Promise.all(promiseTaskList)

      .then(function (result) {

        _this.opt.sources = result;

        _this.opt.currentSource = result[0];

      })

      .catch(function(err){

      })

      return getRealUrlPromiseObj;

    } else {

      if (!this.opt.currentSource) {

        this.log('未找到合适的播放URL');

        return;

      }

      var me = this;

      // 如果不是ezopen打头的，走原来的播放模式

      if (!/^ezopen:\/\//.test(this.opt.currentSource)) {

        this.tryPlay(this.opt.currentSource);

      } else {

        // 如果是ezopen协议地址，先校验一下地址的合法性

        if (!/^ezopen:\/\//.test(this.opt.currentSource)) {

          throw new Error('EZOPEN地址必须要以ezopen://开头');

          return;

        } else if (this.opt.currentSource.indexOf('.com/') === -1) {

          throw new Error('EZOPEN地址格式不正确');

          return;

        } else if (!/[a-z\d]{32}(\.hd)?\.live/.test(this.opt.currentSource)) {

          throw new Error('EZOPEN地址格式uuid格式不正确');

          return;

        } else if (/(.*.hls.*|.*.m3u8.*|.*.wss.*|.*.flv.*|.*.rtmp.*){2,}/.test(this.opt.currentSource)) {

          throw new Error('EZOPEN地址多于两个播放协议');

          return;

        } else if (this.opt.currentSource.search(/(.hls|.m3u8|.wss|.flv|.rtmp)/) !== -1 && !/.live(.hls|.m3u8|.wss|.flv|.rtmp)/.test(this.opt.currentSource)) {

          throw new Error('请指定正确的播放协议');

          return;

        } else if (this.opt.currentSource.search(/(.hls|.m3u8|.wss|.flv|.rtmp)/) === -1 && !/[a-z\d]{32}(\.hd)?\.live$/.test(this.opt.currentSource)) {

          throw new Error('EZOPEN地址结尾不正确');

          return;

        } else {

          /* 获取播放地址 - 开始 */

          var that = this;

          addJs(flv_js, function () {

            var para = {

              "ezopen": that.opt.currentSource,

              "userAgent": window.navigator.userAgent,

              "isFlv": flvjs && flvjs.isSupported() ? flvjs.isSupported() : false,

              "addressTypes": "HLS,RTMP,WS,FLV",

              "isHttp": window.location.protocol.indexOf('s') > 0 ? false : true,

            };



            dclog({

              "ezopen": that.opt.currentSource,

              "userAgent": window.navigator.userAgent,

              "isFlv": flvjs && flvjs.isSupported() ? flvjs.isSupported() : false,

              "addressTypes": "HLS,RTMP,WS,FLV",

              "isHttp": window.location.protocol.indexOf('s') > 0 ? false : true,

              'systemName': 'EZOPEN',

            });



            that.log('---------------------------------------');

            that.log('入参(ezopen)是：   ' + para.ezopen);

            that.log('---------------------------------------');

            that.log('入参(userAgent)是：   ' + para.userAgent);

            that.log('---------------------------------------');

            that.log('入参(isFlv)是：   ' + para.isFlv);

            that.log('---------------------------------------');

            that.log('入参(addressTypes)是：   ' + para.addressTypes);

            that.log('---------------------------------------');

            that.log('入参(isHttp)是：   ' + para.isHttp);

            that.log('---------------------------------------');



            var apiUrl = apiDomain + "/api/lapp/live/url/ezopen";

            var apiSuccess = function (data) {

              if (data.code == 200) {

                that.log('播放地址是：   ' + data.data);

                that.video.src = data.data;

                that.video.load();

                that.tryPlay(data.data);

              } else {

                console.log("平台获取播放地址错误")

                that.log('data：   ' + JSON.stringify(data));

                throw new Error(data.msg);

                return;

              }

            }

            var apiError = function (error) {

              console.log("getdecoder url from api error", error);

            }

            request(apiUrl, 'POST', para, '', apiSuccess, apiError);

          });

        } /* 获取播放地址 - 结束 */

      }

    }

    // 格式化回放时间

    function formatRecTime(time, defaultTime) {

      // 用户格式 无需更改 => 20182626T000000Z

      // return time

      // 用户格式需要更改

      //用户时间长度为 14 20181226000000  =》 20181226000000

      // 用户长度为12     201812260000    =》 201812260000 + defaultTime后面2位

      // 用户长度为10     2018122600      =》 201812260000 + defaultTime后面4位

      // 用户长度为8     20181226         =》 201812260000 + defaultTime后面6位

      // 结果 20181226000000 14位

      // 插入 TZ

      var reg = /^[0-9]{8}T[0-9]{6}Z$/;

      if (reg.test(time)) { // 用户格式 无需更改 => 20182626T000000Z

        return time;

      } else if (/[0-9]{8,14}/.test(time)) {

        var start = 6 - (14 - time.length);

        var end = defaultTime.length;

        var standardTime = time + defaultTime.substring(start, end);

        return standardTime.slice(0, 8) + 'T' + standardTime.slice(8) + 'Z';

      } else {

        throw new Error('回放时间格式有误，请确认');

      }

    }

  };



  // 尝试播放

  EZUIPlayer.prototype.tryPlay = function (playParams) {

    this.log("开始尝试播放，播放配置参数为：");

    this.log(playParams);

    var _this = this;

    // JSDecoder 播放

    if (playParams && typeof playParams === 'object' && playParams.decoderPath) {

      /** 初始化Decoder */

      // this.initDecoder(playParams);

      // 自动播放

      // if(playParams.autoplay){

      //   console.log('配置了自动播放');

      //   setTimeout(function(){

      //     _this.play();

      //   },2000)

      // }

    } else {

      this.opt.currentSource = playParams;

      var me = this;

      // 如果是HLS地址

      if (/\.m3u8/.test(playParams)) {

        // 如果是手机浏览器环境,或者原生支持HLS播放的,直接使用video标签播放

        // 否则尝试使用hls.js播放，

        // 最后使用flash

        if (isMobile || isNativeSupportHls) {

          this.log('使用原生video');

          this.video.style.heght = this.opt.height = Number(this.opt.width.replace(/px$/g, '')) * 9 / 16 + 'px';

          this.initVideoEvent();

        } else {

          var isPlayUrlHttps = playParams.indexOf('https') !== -1;

          if (isHttps && !isPlayUrlHttps) { //https网站，http视频源安全问题需要flash播放

            addJs(ckplayerJS, function () {

              me.initCKPlayer();

            });

          } else {

            addJs(hlsJS, function () {

              isSupportHls = Hls.isSupported();

              if (isSupportHls) {

                me.log('使用hls.js');

                me.initHLS(playParams);

              } else {

                useFlash = true;

                me.log('2 使用flash');

                addJs(ckplayerJS, function () {

                  me.initCKPlayer();

                });

              }

            });

          }

        }

      } else if (/^rtmp:/.test(playParams)) {

        if (isMobile) {

          this.opt.cur++;

          this.tryPlay(playParams);

          return;

        } else {

          addJs(ckplayerJS, function () {

            me.initCKPlayer(playParams);

          });

        }

      } else if (/^wss:|^ws:/.test(playParams)) {

        /*

        *   WS协议的JSMpeg的不支持IE11以下的版本

        *   开放平台官网不支持IE8打开，所以官网上面不兼容两个人版本IE9 ，和IE10

        *

        * */

        if (!ltIE11()) {

          addJs(mpegJS, function () {

            me.initJSmpeg(playParams);

          });

        } else {

          alert('WS协议不支持Ie11以下的浏览器！请使用IE11，或者更高版本的浏览器');

          return;

        }

      } else if (/\.flv/.test(this.opt.currentSource)) {

        addJs(flv_js, function () {

          me.log("使用flv.js播放");
          console.log('=========================')
          console.log(flv_js)
          console.log('=========================')

          me.initflv();

        });

      }

    }

  };



  // 初始化hls.js

  EZUIPlayer.prototype.initHLS = function (hlsURL) {

    var me = this;

    var hls = new Hls({ defaultAudioCodec: 'mp4a.40.2' }); // 萤石设备默认使用 AAC LC 音频编码

    hls.loadSource(hlsURL);

    hls.attachMedia(this.video);

    hls.on(Hls.Events.MANIFEST_PARSED, function () {

      if (me.opt.autoplay) {

        me.video.play();

      }

      me.initVideoEvent();

    });

    hls.on(Hls.Events.ERROR, function (event, data) {

      if (data.fatal) {

        switch (data.type) {

          case Hls.ErrorTypes.NETWORK_ERROR:

            // try to recover network error

            console.log("fatal network error encountered, try to recover");

            hls.startLoad();

            break;

          case Hls.ErrorTypes.MEDIA_ERROR:

            console.log("fatal media error encountered, try to recover");

            hls.recoverMediaError();

            break;

          default:

            // cannot recover

            hls.destroy();

            break;

        }

      }

    });



    this.hls = hls;

  };



  // 日志

  EZUIPlayer.prototype.log = function (msg) {

    this.emit('log', msg);

  };



  // 初始化ckplayer

  EZUIPlayer.prototype.initCKPlayer = function (url) {

    this.log('ckplayer初始化');

    var me = this;

    var events = {

      'play': function () { me.emit('play') },

      'pause': function () { me.emit('pause') },

      'error': function () { me.emit('error') }

    };

    window.ckplayer_status = function () {

      me.log(arguments);

      events[arguments[0]] && events[arguments[0]]();

    };



    // 新增相同id的div标签，然后删除video标签

    this.videoFlash = document.createElement('DIV');

    this.video.parentNode.replaceChild(this.videoFlash, this.video);

    this.video = this.videoFlash;

    this.videoFlash.id = this.opt.parentId;

    var flashvars = null;

    // 如果rtmp服务器环境设置了视频暂停则断开链接

    // 需要修改ckplayer.js  setup参数第30个值

    // 在播放暂停后点击播放是否采用重新链接的方式

    if (/^rtmp/.test(this.opt.currentSource)) {

      flashvars = {

        f: this.opt.currentSource,

        c: 0,

        p: this.opt.autoplay ? 1 : 0,

        i: this.opt.poster,

        lv: 1,

        loaded: 'loadHandler'

      };

    } else if (/\.m3u8/.test(this.opt.currentSource)) {

      flashvars = {

        s: 4,  // 4-使用swf视频流插件播放

        f: m3u8SWF,

        a: this.opt.currentSource,

        c: 0,  // 0-使用ckplayer.js的配置 1-使用ckplayer.xml的配置

        lv: 1, // 1-直播 0-普通方式

        p: this.opt.autoplay ? 1 : 0,   // 1-默认播放 0-默认暂停

        i: this.opt.poster,

        loaded: 'loadHandler'

      };

    } else {

      flashvars = {

        f: this.opt.currentSource,

        c: 0,

        p: 1,

        loaded: 'loadHandler'

      };

    }

    var params = { bgcolor: '#FFF', allowFullScreen: true, allowScriptAccess: 'always', wmode: 'transparent' };

    this.flashId = this.opt.parentId + 'flashId';

    window.CKobject.embedSWF(ckplayerSWF, this.opt.parentId, this.flashId, this.opt.width, this.opt.height, flashvars, params);

  };



  EZUIPlayer.prototype.initVideoEvent = function () {

    var me = this;

    var EVENT = {

      'loadstart': function (e) {

        me.log('loadstart...当浏览器开始查找音频/视频时...');

        me.emit('loadstart', e);

      },

      'durationchange': function (e) {

        me.log('durationchange...当音频/视频的时长已更改时...');

        me.emit('durationchange', e);

      },

      'loadedmetadata': function (e) {

        me.log('loadedmetadata...当浏览器已加载音频/视频的元数据时...');

        me.emit('loadedmetadata', e);

      },

      'loadeddata': function (e) {

        me.log('loadeddata...当浏览器已加载音频/视频的当前帧时...');

        me.emit('loadeddata', e);

      },

      'progress': function (e) {

        me.log('progress...当浏览器正在下载音频/视频时...');

        me.emit('progress', e);

      },

      'canplay': function (e) {

        me.log('canplay...当浏览器可以播放音频/视频时...');

        me.emit('canplay', e);

      },

      'canplaythrough': function (e) {

        me.log('canplaythrough...当浏览器可在不因缓冲而停顿的情况下进行播放时...');

        me.emit('canplaythrough', e);

      },

      'abort': function (e) {

        me.log('abort...当音频/视频的加载已放弃时...');

        me.emit('abort', e);

      },

      'emptied': function (e) {

        me.log('emptied...当目前的播放列表为空时...');

        me.emit('emptied', e);

      },

      'ended': function (e) {

        me.log('ended...当目前的播放列表已结束时...');

        me.emit('ended', e);

      },

      'pause': function (e) {

        me.log('pause...当音频/视频已暂停时...');

        me.emit('pause', e);

      },

      'play': function (e) {

        me.log('play...当音频/视频已开始或不再暂停时...');

        me.emit('play', e);

      },

      'playing': function (e) {

        me.log('playing...当音频/视频在已因缓冲而暂停或停止后已就绪时...');

        me.emit('playing', e);

      },

      'ratechange': function (e) {

        me.log('ratechange...当音频/视频的播放速度已更改时...');

        me.emit('ratechange', e);

      },

      'seeked': function (e) {

        me.log('seeked...当用户已移动/跳跃到音频/视频中的新位置时...');

        me.emit('seeked', e);

      },

      'seeking': function (e) {

        me.log('seeking...当用户开始移动/跳跃到音频/视频中的新位置时...');

        me.emit('seeking', e);

      },

      'stalled': function (e) {

        me.log('stalled...当浏览器尝试获取媒体数据，但数据不可用时...');

        me.emit('stalled', e);

      },

      'suspend': function (e) {

        me.log('suspend...当浏览器刻意不获取媒体数据时...');

        me.emit('suspend', e);

        if (me.opt.autoplay) {

          me.video.play();

        }

      },

      'timeupdate': function (e) {

        //me.log('timeupdate...当目前的播放位置已更改时...');

        me.emit('timeupdate', e);

      },

      'volumechange': function (e) {

        me.log('volumechange...当音量已更改时...');

        me.emit('volumechange', e);

      },

      'waiting': function (e) {

        me.log('waiting...当视频由于需要缓冲下一帧而停止...');

        me.emit('waiting', e);

      },

      'error': function (e) {

        me.log('error...当在音频/视频加载期间发生错误时...');

        me.emit('error', e);

      }



    };

    for (var i in EVENT) {

      this.video.addEventListener(i, EVENT[i], false);

    }



    ios11Hack(this.video);



  };



  EZUIPlayer.prototype.initJSmpeg = function (jsmpegUrl) {

    this.canvasEle = document.createElement('canvas');

    this.canvasEle.style.width = this.opt.width;

    this.canvasEle.style.height = this.opt.height;

    this.video.parentNode.replaceChild(this.canvasEle, this.video);

    this.canvasEle.id = this.opt.parentId;

    var player;

    if (player && player.destroy) {

      player.destroy();

    }

    player = new JSMpeg.Player(jsmpegUrl, { canvas: this.canvasEle });

    this.JSmpeg = player;

  };



  EZUIPlayer.prototype.initflv = function () {

    if (flvjs.isSupported()) {

      var player = this.video;

      var hasControls = player.getAttribute('controls');

      if (!hasControls) {

        player.setAttribute('controls', true);

      }

      var flvPlayer = flvjs.createPlayer({

        type: 'flv',

        url: this.opt.currentSource,

        isLive: true,

      }, {

          enableStashBuffer: true,

          stashInitialSize: 128,

          enableWorker: true

        });



      flvPlayer.attachMediaElement(player);

      flvPlayer.load();

      flvPlayer.play();

    } else {

      this.log("浏览器不支持flv播放");

      throw new Error('浏览器不支持flv播放');

      return;

    }

    this.flv = flvPlayer;

  };





  EZUIPlayer.prototype.play = function (params) {

    //var index = params.index;

    this.log("开始播放" + this.opt.currentSource);

    if (!!window['CKobject']) {

      this.opt.autoplay = true;

      this.initCKPlayer();

    } else if (!!this.video) { // video播放 包含flv, hls

      if (!!this.hls) { // hls开始播放依赖 this.hls

        this.opt.autoplay = true;

        this.hls.startLoad();

        this.video.play();

      } else if (!!this.JSmpeg) {

        this.JSmpeg.play();

      } else {       // 其他开始播放使用原生video

        this.opt.autoplay = true;

        this.video.play();

      }

    } else if (!!this.jSPlugin) {

      var _this = this;

      // 默认开启第一路声音

      setTimeout(function(){

        _this.log("默认开启第一路声音")

        //_this.jSPlugin.JS_OpenSound(0);

      },5000)

      function getPlayParams(url) {

        var websocketConnectUrl = url.split('?')[0].replace('/live', '').replace('/playback', '');

        var websocketStreamingParam = (url.indexOf('/live')=== -1 ? '/playback?': '/live?') + url.split('?')[1];

        return { websocketConnectUrl: websocketConnectUrl, websocketStreamingParam: websocketStreamingParam }

      }

      if (!params || typeof params.index === 'undefined') {

        _this.opt.sources.forEach(function (item, index) {

          _this.jSPlugin.JS_Play(getPlayParams(item).websocketConnectUrl, { playURL: getPlayParams(item).websocketStreamingParam }, index).then(function () {

            console.log("realplay success");

            if (params && params.handleSuccess) {

              params.handleSuccess();

            }

          }, function (err) {

            console.log("realplay failed", err.oError);

            if (params && params.handleError) {

              var errorInfo = JSON.parse(_this.errorCode).find(function(item){return item.detailCode.substr(-4) == err.oError.errorCode})

              params.handleError({retcode: err.oError.errorCode,msg: errorInfo ? errorInfo.description :  '其他错误'});

            }

          })

        })

      } else {

        params.index.forEach(function (item, index) {

          _this.jSPlugin.JS_Play(getPlayParams(_this.opt.sources[item]).websocketConnectUrl, { playURL: getPlayParams(_this.opt.sources[item]).websocketStreamingParam }, item).then(function () {

            console.log("realplay success");

            if (params && params.handleSuccess) {

              params.handleSuccess();

            }

          }, function (err) {

            console.log("realplay failed", err.oError);

            if (params && params.handleError) {

              var errInfo = err.oError;// 包装错误码

              params.handleError(errInfo);

            }

          })

        })

      }

    }



  };

  EZUIPlayer.prototype.initDecoder = function (playParams) {

    this.opt.id = playParams.id;

    this.log("初始化解码器---开始");

    var _this = this;

    // DOM id

    function initDecoder(resolve, reject) {

      var jsPluginPath = playParams.decoderPath + '/js/jsPlugin-1.2.0_test.js';



      /** 初始化解码器 */

      addJs(jsPluginPath, function () {

        _this.log("下载解码器完成，开始初始化");

        /* decoder 属性配置 */

        _this.jSPlugin = new JSPlugin({

          szId: playParams.id,

          iType: 1,

          iWidth: playParams.width || 600,

          iHeight: playParams.height || 400,

          //iMaxSplit: Math.ceil(Math.sqrt(playParams.url.split(",").length)),

          iMaxSplit:4,

          iCurrentSplit: playParams.splitBasis || Math.ceil(Math.sqrt(playParams.url.split(",").length)),

          szBasePath: playParams.decoderPath + '/js',

        });

          // 注册全屏事件

        window.onresize = function () {

          _this.jSPlugin.JS_Resize(playParams.width || 600, playParams.height || 400);

        }

        _this.log("初始化解码器----完成");

        _this.log("开始设置秘钥");

        var validateCode = _this.opt.validateCode;

        if(validateCode){

          _this.jSPlugin.JS_SetSecretKey(0, validateCode);

        }

        resolve('200 OK')

      });

      /**

       * 加载错误码

       * 错误码维护平台 - omm管理系统

       */

      function success(data) {

        if (data.code == 200) {

          if (!window.localStorage) {

            return false;

          } else {

            var storage = window.localStorage;

            //写入a字段

            storage["errorCode"] = JSON.stringify(data.data);

            _this.errorCode = storage['errorCode'];

          }

        }

      }

      if (!window.localStorage) {

        request(

          playParams.decoderPath + "/js/errorCode.json",

          "get",

          {

            language: 1,

            time: new Date().getTime(),

            appKey: '26810f3acd794862b608b6cfbc32a6b8',

          },

          '',

          success

        );

      } else {

        var storage = window.localStorage;

        var errorCode=storage.errorCode;

        if(!errorCode){

          request(

            playParams.decoderPath + "/js/errorCode.json",

            "get",

            {

              language: 1,

              time: new Date().getTime(),

              appKey: '26810f3acd794862b608b6cfbc32a6b8',

            },

            '',

            success

          );

        } else {

          _this.errorCode = storage['errorCode'];

        }

      }





    }

    var initDecoderPromise = new Promise(initDecoder);



    return initDecoderPromise;

  }

  EZUIPlayer.prototype.stop = function (i) {

    // 执行停止

    this.log("停止播放" + this.opt.currentSource);

    this.opt.autoplay = false;

    if (!!window['CKobject']) {

      //CKobject.getObjectById(this.flashId).destroy();

      this.video.src=""

      // this.video.remove();

    } else if (!!this.video) {

      if (!!this.hls) {   // hls停止依赖this.hls

        // 通过暂停停止播放

        this.video.pause();

        this.video.src=""

        // 停止取流

        this.hls.stopLoad();

      } else if (!!this.flv) {

        this.flv.pause();

        this.flv.unload();

        this.flv.detachMediaElement();

        this.flv.destroy();

        this.flv = null;

      } else if (!!this.JSmpeg) {

        this.JSmpeg.stop();

        // this.JSmpeg.destroy();

      }

    } else if (!!this.jSPlugin) {

      var _this = this;

      if (typeof i === "undefined") {

        var length = this.opt.sources.length;

        for (index = 0; index < length; index++) {

          this.jSPlugin.JS_Stop(index).then(function () {

            _this.log("停止播放成功" + _this.opt.currentSource);

            console.log("stop success");

          }, function () {

            _this.log("停止播放失败" + _this.opt.currentSource);

            console.log("stop failed");

          });

          // 额外销毁worker

          //this.jSPlugin.JS_DestroyWorker();

          removeChild(index);

        }

      } else {

        this.jSPlugin.JS_Stop(i).then(function () {

          _this.log("停止播放成功" + _this.opt.currentSource);

          console.log("stop success");

        }, function () {

          _this.log("停止播放失败" + _this.opt.currentSource);

          console.log("stop failed");

        });

        // 额外销毁worker

        //this.jSPlugin.JS_DestroyWorker();

        removeChild(i);

      }

      function removeChild(index) {

        var windDOM = document.getElementById(_this.opt.id).childNodes[0].childNodes[index];

        var childs = windDOM.childNodes;

        for (var i = childs.length - 1; i >= 0; i--) {

          windDOM.removeChild(childs[i]);

        }

      }

    }

  };

  // 获取OSD时间

  EZUIPlayer.prototype.getOSDTime = function(callback,iWind){

    if (!!this.jSPlugin){

      this.jSPlugin.JS_GetOSDTime(iWind || 0).then(function(iTime){

        callback(iTime * 1000);

      }, function (err) {

        console.log("get OSD Time error", err);

      });

    }else {

      throw new Error("Method  not support");

    }

  }

  // 开启声音

  EZUIPlayer.prototype.openSound = function(iWind){

    if (!!this.jSPlugin){

      this.jSPlugin.JS_OpenSound(iWind || 0)

    }else {

      throw new Error("Method  not support");

    }

  }



  // 关闭声音

  EZUIPlayer.prototype.closeSound = function(iWind){

    if (!!this.jSPlugin){

      this.jSPlugin.JS_CloseSound(iWind || 0)

    }else {

      throw new Error("Method  not support");

    }

  }

  EZUIPlayer.prototype.pause = function () {

    this.opt.autoplay = false;

    if (!!window['CKobject']) {

      CKobject.getObjectById(this.flashId).videoPause();

    } else if (!!this.video) {

      if (!!this.JSmpeg) {

        this.JSmpeg.pause();

      } else {

        this.video.pause();

      }

    } else if (!!this.jSPlugin) {

      this.jSPlugin.JS_Pause(0).then(function () {

      }, function () {

      });

    }

  };



  EZUIPlayer.prototype.load = function () {

    if (!!window['CKobject']) {

      // flash load

    } else if (!!this.video) {

      this.video.load();

    }

  };





  // iOS11手机HLS直播在m3u8响应时间过长后不继续请求的hack

  function ios11Hack(video) {

    var isloadeddata = false;

    var isPlaying = false;

    var stalledCount = 0;

    video.addEventListener('loadeddata', function () {

      isloadeddata = true;

    }, false);

    video.addEventListener('stalled', function () {

      stalledCount++;

      if (!isPlaying) {

        if (stalledCount >= 2 && !isloadeddata) {

          video.load();

          video.play();

          isloadeddata = false;

          isPlaying = false;

          stalledCount = 0;

        }

      }

    }, false);

    video.addEventListener('playing', function () {

      isPlaying = true;

    });

  }



  function ltIE11() {

    var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串

    var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1; //判断是否IE<11浏览器

    if (isIE) {

      return true;

    } else {

      return false;

    }

  }



  // 判断浏览器终端类型

  function browserTerminal() {

    var u = window.navigator.userAgent;

    var browserClass = {

      trident: u.indexOf('Trident') > -1, //IE内核

      presto: u.indexOf('Presto') > -1, //opera内核

      webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核

      gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') === -1, //火狐内核

      mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否为移动终端

      ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端

      android: u.indexOf('Android') > -1 || u.indexOf('Adr') > -1, //android终端

      iPhone: u.indexOf('iPhone') > -1, //是否为iPhone或者QQHD浏览器

      iPad: u.indexOf('iPad') > -1, //是否iPad

      webApp: u.indexOf('Safari') == -1, //是否web应该程序，没有头部与底部

      weixin: u.indexOf('MicroMessenger') > -1, //是否微信

      qq: u.match(/\sQQ/i) == " qq", //是否QQ

      ie: u.indexOf('Trident') > -1 || u.indexOf('MSIE') > -1 || u.indexOf('compatible') > -1,

    };

    return browserClass;

  }





  //公共方法

  var Util = {

    //初始化

    init: function () {

      navigator.getUserMedia = navigator.getUserMedia ||

        navigator.webkitGetUserMedia ||

        navigator.mozGetUserMedia ||

        navigator.msGetUserMedia;



      window.AudioContext = window.AudioContext ||

        window.webkitAudioContext;

    },

    //日志

    log: function (str) {

      console.log.apply(console, arguments);

    }

  };





  var EZUITalk = function (bizParams) {

    if (bizParams && typeof bizParams !== 'object') {

      throw new Error("EZUITalk requires parameter it doesn't right");

      return;

    }

    var audioId = bizParams.id;

    var Token = bizParams.token;

    var uuid = bizParams.uuid;

    if (typeof audioId !== 'string' || typeof audioId === 'undefined') {

      throw new Error('EZUITalk requires parameter audioId');

      return;

    }

    this.audio = document.getElementById(audioId);

    if (!this.audio) {

      throw new Error('EZUITalk requires parameter audioElement');

      return;

    }

    if (!Token) {

      throw new Error('EZUITalk requires parameter accessToken');

      return

    }

    if (!uuid) {

      throw new Error('EZUITalk requires parameter uuid');

      return;

    }

    Util.init();

    if (!navigator.getUserMedia) {

      throw new Error('当前浏览器不支持录音功能');

      return;

    }

    var browserC = browserTerminal();

    if (!browserC.mobile) {

      throw new Error('对讲功能仅在手机中支持进行对讲');

      return;

    }



    // 事件存储

    this.handlers = {};

    var _this = this;

    this.BUFFER = [];

    this.encoder = undefined;





    this.isEnded = true;

    this.LENGTH = 20;

    this.audio.addEventListener('ended', function () {

      _this.isEnded = true;

    });



    // 对讲的播放功能

    this.audioPlay = function () {

      if (this.isEnded) {

        this.isEnded = false;

        if (this.BUFFER.length > this.LENGTH) {

          this.BUFFER = this.BUFFER.slice(0, this.LENGTH)

        }

        this.encoder = new WavAudioEncoder(16000, 1);

        var buf = this.BUFFER.shift();

        while (buf) {

          this.encoder.encode(buf);

          buf = this.BUFFER.shift();

        }

        this.audio.src = URL.createObjectURL(this.encoder.finish());

      }

    };



    // 按钮触发对讲功能

    this.start = function () {

      this.wsUrl = 'wss://test2.ys7.com:20007/opentalk/' + uuid;

      this.socket = new WebSocket(this.wsUrl);

      this.talk();

    };



    this.talk = function () {

      addJs(wav, function () {

        _this.socket.onopen = function () {

          _this.log('websocket已连接');

          var sendData = {

            'accessToken': Token,

            'uuid': uuid,

          };

          var messageJson = JSON.stringify(sendData);

          _this.socket.send(messageJson);

          _this.log('websocket 发送文本数据');

          _this.startRecord();

        };

        _this.socket.onclose = function () {

          _this.log('websocket已关闭');

        };

        _this.socket.onerror = function (e) {

          _this.log('websocket出错->' + JSON.stringify(e));

        };

        _this.socket.onmessage = function (e) {

          _this.log('websocket 接收数据');

          _this.BUFFER.push(e.data);

          _this.audioPlay();

        };



        _this.audio.setAttribute('autoplay', true);

        _this.audio.play();



      });

    };



    // 对讲中的说话功能

    this.startRecord = function () {

      navigator.mediaDevices.getUserMedia({ audio: true })

        .then(function (stream) {

          var context = new AudioContext(),

            microphone = context.createMediaStreamSource(stream), //媒体流音频源

            processor = context.createScriptProcessor(16384, 1, 1); //js音频处理器



          _this.log('当前浏览器采样率为： ' + context.sampleRate);



          processor.onaudioprocess = function (event) {

            //监听音频录制过程

            var array = event.inputBuffer.getChannelData(0);

            // _this.log('监听声音录制');

            realTimeWorker.postMessage({ cmd: 'encode', buf: array });

          };



          var realTimeWorker = new Worker('../js/worker.js'); //开启后台线程



          realTimeWorker.onmessage = function (e) {

            //主线程监听后台线程，实时通信

            switch (e.data.cmd) {

              case 'pcm':

                _this.socket.send(e.data.buf);

                console.log(e.data.buf);

                _this.log('websocket 发送数据');

                break;

              default:

                _this.log('未知信息：' + e.data);

            }

          };



          //开始对讲

          if (processor && microphone) {

            microphone.connect(processor);

            processor.connect(context.destination);

          }

          _this.log('开始对讲');



          //结束对讲

          _this.stop = function () {

            if (processor && microphone) {

              microphone.disconnect();

              processor.disconnect();

            }

            _this.socket.close();

            _this.log('结束对讲');

          };



        }).catch(function (error) {

          var msg;

          switch (error.code || error.name) {

            case 'PermissionDeniedError':

            case 'PERMISSION_DENIED':

            case 'NotAllowedError':

              msg = '用户拒绝访问麦克风';

              break;

            case 'NOT_SUPPORTED_ERROR':

            case 'NotSupportedError':

              msg = '浏览器不支持麦克风';

              break;

            case 'MANDATORY_UNSATISFIED_ERROR':

            case 'MandatoryUnsatisfiedError':

              msg = '找不到麦克风设备';

              break;

            default:

              msg = '无法打开麦克风，异常信息:' + (error.code || error.name);

              break;

          }

          _this.log(msg);

          alert(msg);

        })

    }

  };



  // 事件监听

  EZUITalk.prototype.on = function (eventName, callback) {

    if (typeof eventName !== 'string' || typeof callback !== 'function') {

      return;

    }

    if (typeof this.handlers[eventName] === 'undefined') {

      this.handlers[eventName] = [];

    }

    this.handlers[eventName].push(callback);

  };



  // 事件触发

  EZUITalk.prototype.emit = function () {

    if (this.handlers[arguments[0]] instanceof Array) {

      var handlers = this.handlers[arguments[0]];

      var l = handlers.length;

      for (var i = 0; i < l; i++) {

        handlers[i].apply(this, Array.prototype.slice.call(arguments, 1));

      }

    }

  };



  EZUITalk.prototype.log = function (msg) {

    this.emit('log', msg);

  };



  var EZUIKit = {

    'EZUIPlayer': EZUIPlayer,

    'EZUITalk': EZUITalk,

  };

  // 兼容1.4 以下旧版本

  // var EZUIPlayer = EZuikit.EZUIPlayer;



  if (!noGlobal) {

    window.EZUIKit = EZUIKit;

    // 兼容1.4 以下旧版本

    window.EZUIPlayer = EZUIPlayer;

  }

  return EZUIKit;

});

