diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index 23585dd048..97b54f035d 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -201,112 +201,136 @@ class Html5 extends Tech { } /** - * Attempt to force override of native audio/video tracks. + * Attempt to force override of tracks for the given type * + * @param {String} type - Track type to override, possible values include 'Audio', + * 'Video', and 'Text'. * @param {Boolean} override - If set to true native audio/video will be overridden, * otherwise native audio/video will potentially be used. + * @private */ - overrideNativeTracks(override) { + overrideNative_(type, override) { // If there is no behavioral change don't add/remove listeners - if (override !== (this.featuresNativeAudioTracks && this.featuresNativeVideoTracks)) { + if (override !== this[`featuresNative${type}Tracks`]) { return; } - if (this.audioTracksListeners_) { - Object.keys(this.audioTracksListeners_).forEach((eventName) => { - const elTracks = this.el().audioTracks; - - elTracks.removeEventListener(eventName, this.audioTracksListeners_[eventName]); - }); - } + const lowerCaseType = type.toLowerCase(); - if (this.videoTracksListeners_) { - Object.keys(this.videoTracksListeners_).forEach((eventName) => { - const elTracks = this.el().videoTracks; + if (this[`${lowerCaseType}TracksListeners_`]) { + Object.keys(this[`${lowerCaseType}TracksListeners_`]).forEach((eventName) => { + const elTracks = this.el()[`${lowerCaseType}Tracks`]; - elTracks.removeEventListener(eventName, this.videoTracksListeners_[eventName]); + elTracks.removeEventListener(eventName, this[`${lowerCaseType}TracksListeners_`][eventName]); }); } - this.featuresNativeVideoTracks = !override; - this.featuresNativeAudioTracks = !override; + this[`featuresNative${type}Tracks`] = !override; + this[`${lowerCaseType}TracksListeners_`] = null; - this.audioTracksListeners_ = null; - this.videoTracksListeners_ = null; + this.proxyNativeTracksForType_(lowerCaseType); + } - this.proxyNativeTracks_(); + /** + * Attempt to force override of native audio tracks. + * + * @param {Boolean} override - If set to true native audio will be overridden, + * otherwise native audio will potentially be used. + */ + overrideNativeAudioTracks(override) { + this.overrideNative_('Audio', override); } /** - * Proxy all native track list events to our track lists if the browser we are playing - * in supports that type of track list. + * Attempt to force override of native video tracks. * + * @param {Boolean} override - If set to true native video will be overridden, + * otherwise native video will potentially be used. + */ + overrideNativeVideoTracks(override) { + this.overrideNative_('Video', override); + } + + /** + * Proxy native track list events for the given type to our track + * lists if the browser we are playing in supports that type of track list. + * + * @param {string} name - Track type; values include 'audio', 'video', and 'text' * @private */ - proxyNativeTracks_() { - TRACK_TYPES.names.forEach((name) => { - const props = TRACK_TYPES[name]; - const elTracks = this.el()[props.getterName]; - const techTracks = this[props.getterName](); - - if (!this[`featuresNative${props.capitalName}Tracks`] || - !elTracks || - !elTracks.addEventListener) { - return; + proxyNativeTracksForType_(name) { + const props = TRACK_TYPES[name]; + const elTracks = this.el()[props.getterName]; + const techTracks = this[props.getterName](); + + if (!this[`featuresNative${props.capitalName}Tracks`] || + !elTracks || + !elTracks.addEventListener) { + return; + } + const listeners = { + change(e) { + techTracks.trigger({ + type: 'change', + target: techTracks, + currentTarget: techTracks, + srcElement: techTracks + }); + }, + addtrack(e) { + techTracks.addTrack(e.track); + }, + removetrack(e) { + techTracks.removeTrack(e.track); } - const listeners = { - change(e) { - techTracks.trigger({ - type: 'change', - target: techTracks, - currentTarget: techTracks, - srcElement: techTracks - }); - }, - addtrack(e) { - techTracks.addTrack(e.track); - }, - removetrack(e) { - techTracks.removeTrack(e.track); - } - }; - const removeOldTracks = function() { - const removeTracks = []; - - for (let i = 0; i < techTracks.length; i++) { - let found = false; + }; + const removeOldTracks = function() { + const removeTracks = []; - for (let j = 0; j < elTracks.length; j++) { - if (elTracks[j] === techTracks[i]) { - found = true; - break; - } - } + for (let i = 0; i < techTracks.length; i++) { + let found = false; - if (!found) { - removeTracks.push(techTracks[i]); + for (let j = 0; j < elTracks.length; j++) { + if (elTracks[j] === techTracks[i]) { + found = true; + break; } } - while (removeTracks.length) { - techTracks.removeTrack(removeTracks.shift()); + if (!found) { + removeTracks.push(techTracks[i]); } - }; + } - this[props.getterName + 'Listeners_'] = listeners; + while (removeTracks.length) { + techTracks.removeTrack(removeTracks.shift()); + } + }; - Object.keys(listeners).forEach((eventName) => { - const listener = listeners[eventName]; + this[props.getterName + 'Listeners_'] = listeners; - elTracks.addEventListener(eventName, listener); - this.on('dispose', (e) => elTracks.removeEventListener(eventName, listener)); - }); + Object.keys(listeners).forEach((eventName) => { + const listener = listeners[eventName]; - // Remove (native) tracks that are not used anymore - this.on('loadstart', removeOldTracks); - this.on('dispose', (e) => this.off('loadstart', removeOldTracks)); + elTracks.addEventListener(eventName, listener); + this.on('dispose', (e) => elTracks.removeEventListener(eventName, listener)); }); + // Remove (native) tracks that are not used anymore + this.on('loadstart', removeOldTracks); + this.on('dispose', (e) => this.off('loadstart', removeOldTracks)); + } + + /** + * Proxy all native track list events to our track lists if the browser we are playing + * in supports that type of track list. + * + * @private + */ + proxyNativeTracks_() { + TRACK_TYPES.names.forEach((name) => { + this.proxyNativeTracksForType_(name); + }); } /** diff --git a/src/js/tech/tech.js b/src/js/tech/tech.js index cbabf068d3..8a241d472a 100644 --- a/src/js/tech/tech.js +++ b/src/js/tech/tech.js @@ -786,14 +786,24 @@ class Tech extends Component { setPlaysinline() {} /** - * Attempt to force override of native audio.video tracks. + * Attempt to force override of native audio tracks. * - * @param {Boolean} override - If set to true native audio/video will be overridden, - * otherwise native audio/video will potentially be used. + * @param {Boolean} override - If set to true native audio will be overridden, + * otherwise native audio will potentially be used. * * @abstract */ - overrideNativeTracks() {} + overrideNativeAudioTracks() {} + + /** + * Attempt to force override of native video tracks. + * + * @param {Boolean} override - If set to true native video will be overridden, + * otherwise native video will potentially be used. + * + * @abstract + */ + overrideNativeVideoTracks() {} /* * Check if the tech can support the given mime-type. diff --git a/test/unit/tech/html5.test.js b/test/unit/tech/html5.test.js index bb857fb392..2f731b1428 100644 --- a/test/unit/tech/html5.test.js +++ b/test/unit/tech/html5.test.js @@ -550,15 +550,10 @@ if (Html5.supportsNativeAudioTracks()) { rems.push({ type, fn }); } }; - const vt = { - length: 0, - addEventListener: (type, fn) => null, - removeEventListener: (type, fn) => null - }; + const el = document.createElement('div'); el.audioTracks = at; - el.videoTracks = vt; const htmlTech = new Html5({el}); @@ -567,21 +562,21 @@ if (Html5.supportsNativeAudioTracks()) { assert.equal(rems.length, 0, 'no listeners should be removed'); - htmlTech.overrideNativeTracks(true); + htmlTech.overrideNativeAudioTracks(true); assert.equal(adds.length, 3, 'should not have added additional listeners'); assert.equal(rems.length, 3, 'should have removed previous three listeners'); - htmlTech.overrideNativeTracks(true); + htmlTech.overrideNativeAudioTracks(true); assert.equal(adds.length, 3, 'no state change so do not add listeners'); assert.equal(rems.length, 3, 'no state change so do not remove listeners'); - htmlTech.overrideNativeTracks(false); + htmlTech.overrideNativeAudioTracks(false); assert.equal(adds.length, 6, 'should add listeners because native tracks should be proxied'); @@ -673,14 +668,8 @@ if (Html5.supportsNativeVideoTracks()) { rems.push({ type, fn }); } }; - const at = { - length: 0, - addEventListener: (type, fn) => null, - removeEventListener: (type, fn) => null - }; const el = document.createElement('div'); - el.audioTracks = at; el.videoTracks = vt; const htmlTech = new Html5({el}); @@ -690,21 +679,21 @@ if (Html5.supportsNativeVideoTracks()) { assert.equal(rems.length, 0, 'no listeners should be removed'); - htmlTech.overrideNativeTracks(true); + htmlTech.overrideNativeVideoTracks(true); assert.equal(adds.length, 3, 'should not have added additional listeners'); assert.equal(rems.length, 3, 'should have removed previous three listeners'); - htmlTech.overrideNativeTracks(true); + htmlTech.overrideNativeVideoTracks(true); assert.equal(adds.length, 3, 'no state change so do not add listeners'); assert.equal(rems.length, 3, 'no state change so do not remove listeners'); - htmlTech.overrideNativeTracks(false); + htmlTech.overrideNativeVideoTracks(false); assert.equal(adds.length, 6, 'should add listeners because native tracks should be proxied');