在jPlayer中缓冲 [英] Buffering in jPlayer

查看:93
本文介绍了在jPlayer中缓冲的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们使用Icecast流媒体服务器在我们的网站上将jPlayer用作移动应用程序.我试图将<intro>添加到Icecast配置中,但是当我这样做时,它在移动设备上出现了问题.每当电话中断导致临时断开时(例如打进来的电话),流都会重复您首次连接到流时开始播放的内容,当然会再次播放介绍视频.例如,如果我开始收听一个节目或歌曲的流,然后有电话打入并结束,则简介将在重新连接上播放,并且该流将从我最初开始收听的位置开始播放.

We use Icecast streaming server to jPlayer on our website and also used on our mobile app. I was trying to add an <intro> to the Icecast config, but when I do, it presents an issue on mobile devices. Whenever the phone has an interruption causing a temporary disconnect, like a call that comes in, the stream repeats what you started listening to when you first connected to the stream, after the intro plays again of course. For instance, if I start the stream listening to one show or song, a call comes in and ends, the intro plays on the reconnect and the stream plays from where I initially started listening.

我玩过Icecast队列和突发设置,上下都没有,尝试了不同的格式,得到了相同的结果.我还与其他一些与流相关的帖子进行了交谈,并被告知似乎问题出在客户端缓冲区和播放器上,而我没有设置.我看了看我们的stream-player.js,它是jPlayer 2.9.2,在3507行的末尾加上了以下内容:

I have played with Icecast queue and burst settings up and down and none at all, and tried different formats, the same result. I've also had conversations on a couple of other streaming related posts and have been told it seems the issue is with the client buffer and player, which I did not set up. I took a look at our stream-player.js, it is jPlayer 2.9.2 with the following tacked on to the end at line 3507:

;(function() {
  var DOMParser, find, parse;

  DOMParser = (typeof window !== "undefined" && window !== null ? window.DOMParser : void 0) || (typeof require === "function" ? require('xmldom').DOMParser : void 0) || function() {};

  find = function(node, list) {
    var attributes, childNode, childNodeName, childNodes, i, match, x, _i, _j, _ref, _ref1;
    if (node.hasChildNodes()) {
      childNodes = node.childNodes;
      for (i = _i = 0, _ref = childNodes.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
        childNode = childNodes[i];
        childNodeName = childNode.nodeName;
        if (/REF/i.test(childNodeName)) {
          attributes = childNode.attributes;
          for (x = _j = 0, _ref1 = attributes.length; 0 <= _ref1 ? _j < _ref1 : _j > _ref1; x = 0 <= _ref1 ? ++_j : --_j) {
            match = attributes[x].nodeName.match(/HREF/i);
            if (match) {
              list.push({
                file: childNode.getAttribute(match[0]).trim()
              });
              break;
            }
          }
        } else if (childNodeName !== '#text') {
          find(childNode, list);
        }
      }
    }
    return null;
  };

  parse = function(playlist) {
    var doc, ret;
    ret = [];
    doc = (new DOMParser()).parseFromString(playlist, 'text/xml').documentElement;
    if (!doc) {
      return ret;
    }
    find(doc, ret);
    return ret;
  };

  (typeof module !== "undefined" && module !== null ? module.exports : window).ASX = {
    name: 'asx',
    parse: parse
  };

}).call(this);

(function() {
  var COMMENT_RE, EXTENDED, comments, empty, extended, parse, simple;

  EXTENDED = '#EXTM3U';

  COMMENT_RE = /:(?:(-?\d+),(.+)\s*-\s*(.+)|(.+))\n(.+)/;

  extended = function(line) {
    var match;
    match = line.match(COMMENT_RE);
    if (match && match.length === 6) {
      return {
        length: match[1] || 0,
        artist: match[2] || '',
        title: match[4] || match[3],
        file: match[5].trim()
      };
    }
  };

  simple = function(string) {
    return {
      file: string.trim()
    };
  };

  empty = function(line) {
    return !!line.trim().length;
  };

  comments = function(line) {
    return line[0] !== '#';
  };

  parse = function(playlist) {
    var firstNewline;
    playlist = playlist.replace(/\r/g, '');
    firstNewline = playlist.search('\n');
    if (playlist.substr(0, firstNewline) === EXTENDED) {
      return playlist.substr(firstNewline).split('\n#').filter(empty).map(extended);
    } else {
      return playlist.split('\n').filter(empty).filter(comments).map(simple);
    }
  };

  (typeof module !== "undefined" && module !== null ? module.exports : window).M3U = {
    name: 'm3u',
    parse: parse
  };

}).call(this);

(function() {
  var LISTING_RE, parse;

  LISTING_RE = /(file|title|length)(\d+)=(.+)\r?/i;

  parse = function(playlist) {
    var index, key, line, match, tracks, value, _, _i, _len, _ref;
    tracks = [];
    _ref = playlist.trim().split('\n');
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      line = _ref[_i];
      match = line.match(LISTING_RE);
      if (match && match.length === 4) {
        _ = match[0], key = match[1], index = match[2], value = match[3];
        if (!tracks[index]) {
          tracks[index] = {};
        }
        tracks[index][key.toLowerCase()] = value;
      }
    }
    return tracks.filter(function(track) {
      return track != null;
    });
  };

  (typeof module !== "undefined" && module !== null ? module.exports : window).PLS = {
    name: 'pls',
    parse: parse
  };

}).call(this);
;(function() {
  var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

  window.PlayerUI = (function() {
    function PlayerUI(container) {
      var _this = this;
      this.container = container;
      this.onStateButtonClicked = __bind(this.onStateButtonClicked, this);
      this.duration = null;
      this.state = 'loading';
      this.player = $('<div></div>');
      this.container.append(this.player);
      this.player.jPlayer({
        ready: function() {
          return _this.state = 'paused';
        }
      });
      this.volume = this.container.find('.volume-slider input').rangeslider({
        polyfill: false,
        onSlide: function(position, value) {
          return _this.player.jPlayer('volume', value / 100.0);
        },
        onSlideEnd: function(position, value) {
          return _this.player.jPlayer('volume', value / 100.0);
        }
      });
      this.hookEvents();
    }

    PlayerUI.prototype.hookEvents = function() {
      var _this = this;
      this.container.find('.state-button a').click(this.onStateButtonClicked);
      this.player.on($.jPlayer.event.play, function() {
        return _this.setState('playing');
      });
      this.player.on($.jPlayer.event.pause, function() {
        return _this.setState('paused');
      });
      this.player.on($.jPlayer.event.durationchange, function(e) {
        return _this.container.trigger('player.setProgressMax', {
          maxValue: e.jPlayer.status.duration
        });
      });
      this.player.on($.jPlayer.event.timeupdate, function(e) {
        return _this.container.trigger('player.updateProgress', {
          value: e.jPlayer.status.currentTime
        });
      });
      return this.player.on($.jPlayer.event.ended, function(e) {
        return _this.container.trigger('player.trackEnded');
      });
    };

    PlayerUI.prototype.setState = function(state) {
      this.state = state;
      return this.container.find('.state-button a').removeClass().addClass("state-" + state);
    };

    PlayerUI.prototype.onStateButtonClicked = function(event) {
      event.preventDefault();
      switch (this.state) {
        case 'playing':
          return this.pause();
        case 'paused':
          return this.play();
        default:
          return this.noop();
      }
    };

    PlayerUI.prototype.setMedia = function(media) {
      this.pause();
      return this.player.jPlayer('setMedia', media);
    };

    PlayerUI.prototype.setProgress = function(pct) {
      return this.player.jPlayer('playHead', pct);
    };

    PlayerUI.prototype.play = function() {
      this.setState('playing');
      return this.player.jPlayer('play');
    };

    PlayerUI.prototype.pause = function() {
      this.setState('paused');
      return this.player.jPlayer('pause');
    };

    PlayerUI.prototype.noop = function() {
      return null;
    };

    return PlayerUI;

  })();

}).call(this);
;(function() {
  window.PlaylistUI = (function() {
    function PlaylistUI(container) {
      var _this = this;
      this.container = container;
      this.container.hide();
      $(window).on('playlistloader.finished', function(evt, data) {
        return _this.setPlaylist(PlaylistLoader.coalescePlaylists(data.playlists));
      });
    }

    PlaylistUI.prototype.loadM3UList = function(m3uList) {
      return new PlaylistLoader(m3uList);
    };

    PlaylistUI.prototype.setPlaylist = function(playlistData) {
      if (typeof playlistData.data !== 'undefined') {
        this.name = playlistData.name;
        playlistData = playlistData.data;
      }
      this.playlist = playlistData;
      this.container.hide();
      this.unhookEvents();
      this.renderPlaylist();
      this.container.show();
      this.hookEvents();
      return this.container.trigger('playlistui.ready', {
        ui: this,
        autoplay: false //this.getAutoplay()
      });
    };

    PlaylistUI.prototype.unhookEvents = function() {
      return this.container.find('.playlist-item').off('click.playlistUI', 'a');
    };

    PlaylistUI.prototype.hookEvents = function() {
      var _this = this;
      return this.container.find('.playlist-item').on('click.playlistUI', 'a', function(evt) {
        var idx, item;
        evt.preventDefault();
        idx = $(evt.target).parent('.playlist-item').data('idx');
        item = _this.getItemByIdx(idx);
        return _this.select(item);
      });
    };

    PlaylistUI.prototype.renderPlaylist = function() {
      var idx, item, playlist, _i, _len, _ref, _results;
      playlist = this.container.find('.playlist');
      playlist.empty();
      _ref = this.playlist;
      _results = [];
      for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
        item = _ref[idx];
        _results.push(playlist.append(this.rowTemplate(item, idx)));
      }
      return _results;
    };

    PlaylistUI.prototype.rowTemplate = function(item, idx) {
      return $("<li class=\"playlist-item\" data-idx=\"" + idx + "\"><a href=\"" + item.file + "\">" + item.title + "</a></li>");
    };

    PlaylistUI.prototype.getAutoplay = function() {
      var item, _i, _len, _ref;
      _ref = this.playlist;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        item = _ref[_i];
        if (item.autoplay) {
          return item;
        }
      }
      return null;
    };

    PlaylistUI.prototype.getItemByIdx = function(idx) {
      return this.playlist[idx];
    };

    PlaylistUI.prototype.getRowForItem = function(item) {
      var compare, found, idx, _i, _len, _ref;
      _ref = this.playlist;
      for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
        compare = _ref[idx];
        if (compare === item) {
          found = this.container.find(".playlist-item[data-idx=" + idx + "]");
          return found;
        }
      }
      return null;
    };

    PlaylistUI.prototype.getIndexForItem = function(item) {
      var compare, idx, _i, _len, _ref;
      _ref = this.playlist;
      for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
        compare = _ref[idx];
        if (item === compare) {
          return idx;
        }
      }
      return null;
    };

    PlaylistUI.prototype.findNext = function() {
      var currentIndex, nextIndex;
      currentIndex = this.getIndexForItem(this.current);
      if (currentIndex === null) {
        return null;
      }
      nextIndex = currentIndex + 1;
      if (nextIndex >= this.playlist.length) {
        return null;
      }
      return this.playlist[nextIndex];
    };

    PlaylistUI.prototype.select = function(item) {
      if (item) {
          this.current = item;
          this.getRowForItem(item).addClass('selected').siblings().removeClass('selected');
          return this.container.trigger('playlistui.select', {
            ui: this,
            item: item
        });
      }
    };

    PlaylistUI.prototype.selectFirst = function() {
      return this.select(this.playlist[0]);
    };

    PlaylistUI.prototype.selectNext = function() {
      var nextItem;
      nextItem = this.findNext();
      if (nextItem === null) {
        return false;
      }
      this.select(nextItem);
      return true;
    };

    return PlaylistUI;

  })();

}).call(this);
;(function() {
  var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

  window.PlaylistLoader = (function() {
    function PlaylistLoader(playlists) {
      this.playlists = playlists;
      this.loadedItem = __bind(this.loadedItem, this);
      this.loadPlaylists();
    }

    PlaylistLoader.prototype.loadPlaylists = function() {
      var idx, item, _i, _len, _ref, _results,
        _this = this;
      this.loadCount = 0;
      this.data = new Array(this.playlists.length);
      _ref = this.playlists;
      _results = [];
      for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
        item = _ref[idx];
        _results.push((function() {
          var tmp;
          tmp = idx;
          return jQuery.ajax({
            url: item
          }).done(function(data) {
            return _this.loadedItem(tmp, data);
          });
        })());
      }
      return _results;
    };

    PlaylistLoader.prototype.loadedItem = function(idx, data) {
      var playlist;
      playlist = M3U.parse(data);
      this.data[idx] = playlist;
      $(window).trigger('playlistloader.loadeditem', {
        index: idx,
        playlist: playlist
      });
      this.loadCount++;
      if (this.loadCount === this.playlists.length) {
        return this.finishedLoading();
      }
    };

    PlaylistLoader.prototype.finishedLoading = function() {
      return $(window).trigger('playlistloader.finished', {
        playlists: this.data
      });
    };

    PlaylistLoader.coalescePlaylists = function(playlistsLoaded) {
      var fileEntry, output, playlist, _i, _j, _len, _len1;
      output = [];
      for (_i = 0, _len = playlistsLoaded.length; _i < _len; _i++) {
        playlist = playlistsLoaded[_i];
        for (_j = 0, _len1 = playlist.length; _j < _len1; _j++) {
          fileEntry = playlist[_j];
          output.push(fileEntry);
        }
      }
      return output;
    };

    return PlaylistLoader;

  })();

}).call(this);
;(function() {
  var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

  window.StreamUI = (function() {
    function StreamUI(selector, streamPlaylists) {
      this.selector = selector;
      this.streamPlaylists = streamPlaylists;
      this.playlistSelect = __bind(this.playlistSelect, this);
      this.playlistReady = __bind(this.playlistReady, this);
      this.container = jQuery(this.selector);
      this.playlist = new PlaylistUI(this.container.find('.playlist-ui'));
      this.player = new PlayerUI(this.container.find('.player-ui'));
      this.hookEvents();
      this.playlist.loadM3UList(this.streamPlaylists);
    }

    StreamUI.prototype.hookEvents = function() {
      var playlistUI;
      playlistUI = this.container.find('.playlist-ui');
      playlistUI.on('playlistui.ready', this.playlistReady);
      return playlistUI.on('playlistui.select', this.playlistSelect);
    };

    StreamUI.prototype.playlistReady = function(evt, eventinfo) {
      if (eventinfo.autoplay !== null) {
        return eventinfo.ui.select(eventinfo.autoplay);
      } else {
        return eventinfo.ui.selectFirst();
      }
    };

    StreamUI.prototype.playlistSelect = function(evt, eventinfo) {
      this.player.setMedia({
        mp3: eventinfo.item.file
      });
      return this.player.play();
    };

    return StreamUI;

  })();

}).call(this);

尽管我主要是从事Perl和PHP编程工作的Linux开发人员,并且确实很了解jQuery处理我的Web开发,但是对于jPlayer甚至音频流,我无疑是一个新手.我希望有人能在上面的代码中发现某些东西,这可能会导致在向Icecast 2.4.4流添加简介时遇到的问题?

Although I'm primarily a linux developer with most of my programming experience in Perl and PHP, and do know jQuery pretty well dealing with my web development, I'm surely a novice when it comes to jPlayer or even audio streaming. I was hoping someone could spot something in hte code above that could contribute to the issue we have when adding an intro to our Icecast 2.4.4 stream?

我们的流可在下面的URL上找到,目前我对HD4流进行了介绍.

Our streams are available at the URL below, I have the intro on our HD4 stream at the moment.

流媒体播放器

可以通过以下方法轻松地复制该问题:启动流并稍稍听一听,直到歌曲改变为止,然后拨打电话使其中断流,然后挂断电话.在介绍之后,这将导致第一首收听的歌曲再次播放.

The issue is easily duplicated by starting the stream and listening a bit until the song changes, call the phone letting it interrupt the stream, then hang up. This will cause the first song listened to be playing again after the intro.

我相信编解码器是匹配的,在使我的前奏奏效之前确实存在问题,直到我将其格式化为MP3 128Kbps比特率44.1KHz采样和2声道立体声.这是介绍文件信息:

I believe the codec is a match, I did have an issue getting the intro to work until I formatted as MP3 128Kbps bit rate 44.1KHz sampling and 2 channel stereo. Here is the intro file info:

user@stream:~$ mediainfo /usr/share/icecast2/web/high_quality.mp3
General
Complete name                            : /usr/share/icecast2/web/high_quality.mp3
Format                                   : MPEG Audio
File size                                : 138 KiB
Duration                                 : 8s 777ms
Overall bit rate mode                    : Constant
Overall bit rate                         : 128 Kbps
Writing library                          : LAME3.99r

Audio
Format                                   : MPEG Audio
Format version                           : Version 1
Format profile                           : Layer 3
Mode                                     : Joint stereo
Mode extension                           : MS Stereo
Duration                                 : 8s 803ms
Bit rate mode                            : Constant
Bit rate                                 : 128 Kbps
Channel(s)                               : 2 channels
Sampling rate                            : 44.1 KHz
Compression mode                         : Lossy
Stream size                              : 137 KiB (100%)
Writing library                          : LAME3.99r
Encoding settings                        : -m j -V 4 -q 3 -lowpass 17 -b 128

推荐答案

诸如底层浏览器缓存之类的声音开始播放,并强制重播内存中保存的内容.在某些情况下,浏览器很棒",然后将不顾一切地忽略无缓存指令和其他内容.

Sounds like the underlying browser cache kicks in and forces replay of something held in memory. Browsers are 'awesome' like that under some circumstances and will then go out of their way to ignore no-cache directives and other things.

确保浏览器不尝试播放高速缓存恶作剧的一种方法是添加高速缓存破坏者".本质上是查询字符串(/stream?foo = bar),它使浏览器引擎认为它是动态生成的内容并丢弃其缓存; cf. https://www.keycdn.com/support/what-is-cache-破坏.

One way to make sure the browser doesn't try to play cache shenanigans is to add a "cache buster". Essentially a query string ( /stream?foo=bar ), which makes the browser engine think it's dynamically generated content and discard its cache; cf. https://www.keycdn.com/support/what-is-cache-busting .

目前,您的Icecast服务器似乎未回答任何请求.因此,我无法调查您这一方面的具体情况.

At this time your Icecast server doesn't seem to answer any requests. So I can't look into the specifics on your side.

这篇关于在jPlayer中缓冲的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆