From 249532ad457a83c6ca96131d38ad37ffaccf74a6 Mon Sep 17 00:00:00 2001 From: Greg Smith Date: Mon, 2 May 2016 18:54:34 -0400 Subject: [PATCH] @incompl clear currentSource_ after subsequent loadstarts. closes #3285 --- CHANGELOG.md | 1 + src/js/event-target.js | 7 +++++- src/js/tech/html5.js | 1 - src/js/tech/tech.js | 36 ++++++++++++++++++++++++----- test/unit/tech/tech.test.js | 45 ++++++++++++++++++++++++++++++++++++- 5 files changed, 82 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b71dfbb4e..9299a29b80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ CHANGELOG * @gkatsev updated text track documentation and crossorigin warning. Fixes #1888, #1958, #2628, #3202 ([view](https://github.com/videojs/video.js/pull/3256)) * @BrandonOCasey added audio and video track support ([view](https://github.com/videojs/video.js/pull/3173)) * @OwenEdwards added language attribute in HTML files for accessibility ([view](https://github.com/videojs/video.js/pull/3257)) +* @incompl clear currentSource_ after subsequent loadstarts ([view](https://github.com/videojs/video.js/pull/3285)) -------------------- diff --git a/src/js/event-target.js b/src/js/event-target.js index 6d06299fa9..281d2b99c2 100644 --- a/src/js/event-target.js +++ b/src/js/event-target.js @@ -11,7 +11,7 @@ EventTarget.prototype.on = function(type, fn) { // Remove the addEventListener alias before calling Events.on // so we don't get into an infinite type loop let ael = this.addEventListener; - this.addEventListener = Function.prototype; + this.addEventListener = () => {}; Events.on(this, type, fn); this.addEventListener = ael; }; @@ -23,7 +23,12 @@ EventTarget.prototype.off = function(type, fn) { EventTarget.prototype.removeEventListener = EventTarget.prototype.off; EventTarget.prototype.one = function(type, fn) { + // Remove the addEventListener alias before calling Events.on + // so we don't get into an infinite type loop + let ael = this.addEventListener; + this.addEventListener = () => {}; Events.one(this, type, fn); + this.addEventListener = ael; }; EventTarget.prototype.trigger = function(event) { diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index 8957d7700a..aaf84346ec 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -1148,7 +1148,6 @@ Html5.prototype['featuresNativeVideoTracks'] = Html5.supportsNativeVideoTracks() */ Html5.prototype['featuresNativeAudioTracks'] = Html5.supportsNativeAudioTracks(); - // HTML5 Feature detection and Device Fixes --------------------------------- // let canPlayType; const mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i; diff --git a/src/js/tech/tech.js b/src/js/tech/tech.js index 15899caa1c..920192212e 100644 --- a/src/js/tech/tech.js +++ b/src/js/tech/tech.js @@ -814,18 +814,44 @@ Tech.withSourceHandlers = function(_Tech){ if (this.currentSource_) { this.clearTracks(['audio', 'video']); } - this.currentSource_ = source; + + if (sh !== _Tech.nativeSourceHandler) { + + this.currentSource_ = source; + + // Catch if someone replaced the src without calling setSource. + // If they do, set currentSource_ to null and dispose our source handler. + this.off(this.el_, 'loadstart', _Tech.prototype.firstLoadStartListener_); + this.off(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_); + this.one(this.el_, 'loadstart', _Tech.prototype.firstLoadStartListener_); + + } + this.sourceHandler_ = sh.handleSource(source, this, this.options_); this.on('dispose', this.disposeSourceHandler); return this; }; - /* - * Clean up any existing source handler - */ - _Tech.prototype.disposeSourceHandler = function(){ + // On the first loadstart after setSource + _Tech.prototype.firstLoadStartListener_ = function() { + this.one(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_); + }; + + // On successive loadstarts when setSource has not been called again + _Tech.prototype.successiveLoadStartListener_ = function() { + this.currentSource_ = null; + this.disposeSourceHandler(); + this.one(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_); + }; + + /* + * Clean up any existing source handler + */ + _Tech.prototype.disposeSourceHandler = function() { if (this.sourceHandler_ && this.sourceHandler_.dispose) { + this.off(this.el_, 'loadstart', _Tech.prototype.firstLoadStartListener_); + this.off(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_); this.sourceHandler_.dispose(); } }; diff --git a/test/unit/tech/tech.test.js b/test/unit/tech/tech.test.js index 695e2277ee..ef006a810f 100644 --- a/test/unit/tech/tech.test.js +++ b/test/unit/tech/tech.test.js @@ -14,7 +14,6 @@ import AudioTrackList from '../../../src/js/tracks/audio-track-list'; import VideoTrackList from '../../../src/js/tracks/video-track-list'; import TextTrackList from '../../../src/js/tracks/text-track-list'; - q.module('Media Tech', { 'setup': function() { this.noop = function() {}; @@ -370,3 +369,47 @@ test('Tech.isTech returns correct answers for techs and components', function() ok(!isTech(new Button({}, {})), 'A Button instance is not a Tech'); ok(!isTech(isTech), 'A function is not a Tech'); }); + +test('Tech#setSource clears currentSource_ after repeated loadstart', function() { + let disposed = false; + let MyTech = extendFn(Tech); + + Tech.withSourceHandlers(MyTech); + let tech = new MyTech(); + + var sourceHandler = { + canPlayType: function(type) { + return true; + }, + canHandleSource: function(source) { + return true; + }, + handleSource: function(source, tech, options) { + return { + dispose: function() { + disposed = true; + } + }; + } + }; + + // Test registering source handlers + MyTech.registerSourceHandler(sourceHandler); + + // First loadstart + tech.setSource('test'); + tech.currentSource_ = 'test'; + tech.trigger('loadstart'); + equal(tech.currentSource_, 'test', 'Current source is test'); + + // Second loadstart + tech.trigger('loadstart'); + equal(tech.currentSource_, null, 'Current source is null'); + equal(disposed, true, 'disposed is true'); + + // Third loadstart + tech.currentSource_ = 'test'; + tech.trigger('loadstart'); + equal(tech.currentSource_, null, 'Current source is still null'); + +});