Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert 4.12.9 and fix the Html5 tech with sourceHandlers that use MSE #2271

Closed
wants to merge 8 commits into from
43 changes: 38 additions & 5 deletions src/js/media/html5.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,10 +314,20 @@ vjs.Html5.prototype.exitFullScreen = function(){
this.el_.webkitExitFullScreen();
};

vjs.Html5.prototype.returnFakeIfBlobURI_ = function (realValue, fakeValue) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain this with a comment?

var blobURIRegExp = /^blob\:/i;

if (realValue && blobURIRegExp.test(realValue)) {
return fakeValue;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should there be null checking here?

}
return realValue;
};

vjs.Html5.prototype.src = function(src) {
var realSrc = this.el_.src;

if (src === undefined) {
return this.el_.src;
return this.returnFakeIfBlobURI_(realSrc, this.source_);
} else {
// Setting src through `src` instead of `setSrc` will be deprecated
this.setSrc(src);
Expand All @@ -330,11 +340,13 @@ vjs.Html5.prototype.setSrc = function(src) {

vjs.Html5.prototype.load = function(){ this.el_.load(); };
vjs.Html5.prototype.currentSrc = function(){
if (this.currentSource_) {
return this.currentSource_.src;
} else {
return this.el_.currentSrc;
var realSrc = this.el_.currentSrc;

if (!this.currentSource_) {
return realSrc;
}

return this.returnFakeIfBlobURI_(realSrc, this.currentSource_.src);
};

vjs.Html5.prototype.poster = function(){ return this.el_.poster; };
Expand Down Expand Up @@ -470,6 +482,27 @@ vjs.Html5.isSupported = function(){
// Add Source Handler pattern functions to this tech
vjs.MediaTechController.withSourceHandlers(vjs.Html5);

/*
* Override the withSourceHandler mixin's methods with our own because
* the HTML5 Media Element returns blob urls when utilizing MSE and we
* want to still return proper source urls even when in that case
*/
(function(){
var
origSetSource = vjs.Html5.prototype.setSource,
origDisposeSourceHandler = vjs.Html5.prototype.disposeSourceHandler;

vjs.Html5.prototype.setSource = function (source) {
this.source_ = source.src;
return origSetSource.call(this, source);
};

vjs.Html5.prototype.disposeSourceHandler = function () {
this.source_ = undefined;
return origDisposeSourceHandler.call(this);
};
})();

/**
* The default native source handler.
* This simply passes the source to the video element. Nothing fancy.
Expand Down
29 changes: 1 addition & 28 deletions src/js/media/media.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ vjs.MediaTechController = vjs.Component.extend({
this.emulateTextTracks();
}

this.on('loadstart', this.updateCurrentSource_);

this.initTextTrackListeners();
}
});
Expand Down Expand Up @@ -170,24 +168,6 @@ vjs.MediaTechController.prototype.onTap = function(){
this.player().userActive(!this.player().userActive());
};

/**
* Set currentSource_ asynchronously to simulate the media element's
* asynchronous execution of the `resource selection algorithm`
*
* currentSource_ is set either as the first loadstart event OR
* in a timeout to make sure it is set asynchronously before anything else
* but before other loadstart handlers have had a chance to execute
*/
vjs.MediaTechController.prototype.updateCurrentSource_ = function () {
// We could have been called with a 0-ms setTimeout OR via loadstart (which ever
// happens first) so we should clear the timeout to be a good citizen
this.clearTimeout(this.updateSourceTimer_);

if (this.pendingSource_) {
this.currentSource_ = this.pendingSource_;
}
};

/* Fallbacks for unsupported event types
================================================================================ */
// Manually trigger progress events based on changes to the buffered amount
Expand Down Expand Up @@ -446,8 +426,6 @@ vjs.MediaTechController.prototype['featuresNativeTextTracks'] = false;
*
*/
vjs.MediaTechController.withSourceHandlers = function(Tech){
Tech.prototype.currentSource_ = {src: ''};

/**
* Register a source handler
* Source handlers are scripts for handling specific formats.
Expand Down Expand Up @@ -532,12 +510,7 @@ vjs.MediaTechController.withSourceHandlers = function(Tech){
this.disposeSourceHandler();
this.off('dispose', this.disposeSourceHandler);

// Schedule currentSource_ to be set asynchronously
if (source && source.src !== '') {
this.pendingSource_ = source;
this.updateSourceTimer_ = this.setTimeout(vjs.bind(this, this.updateCurrentSource_), 0);
}

this.currentSource_ = source;
this.sourceHandler_ = sh.handleSource(source, this);
this.on('dispose', this.disposeSourceHandler);

Expand Down
7 changes: 1 addition & 6 deletions src/js/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -1228,12 +1228,7 @@ vjs.Player.prototype.load = function(){
* @return {String} The current source
*/
vjs.Player.prototype.currentSrc = function(){
var techSrc = this.techGet('currentSrc');

if (techSrc === undefined) {
return this.cache_.src || '';
}
return techSrc;
return this.techGet('currentSrc') || this.cache_.src || '';
};

/**
Expand Down
56 changes: 1 addition & 55 deletions test/unit/media.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,6 @@ test('should add the source hanlder interface to a tech', function(){

// Pass a source through the source handler process of a tech instance
tech.setSource(sourceA);

// Increment clock since currentSource_ is set asynchronously
this.clock.tick(1);

strictEqual(tech.currentSource_, sourceA, 'sourceA was handled and stored');
ok(tech.sourceHandler_.dispose, 'the handlerOne state instance was stored');

Expand Down Expand Up @@ -254,54 +250,4 @@ test('should handle unsupported sources with the source hanlder API', function()

tech.setSource('');
ok(usedNative, 'native source handler was used when an unsupported source was set');
});

test('should emulate the video element\'s behavior for currentSrc when src is set', function(){
var mockPlayer = {
off: this.noop,
trigger: this.noop
};
var sourceA = { src: 'foo.mp4', type: 'video/mp4' };
var sourceB = { src: '', type: 'video/mp4' };

// Define a new tech class
var Tech = videojs.MediaTechController.extend();

// Extend Tech with source handlers
vjs.MediaTechController.withSourceHandlers(Tech);

// Create an instance of Tech
var tech = new Tech(mockPlayer);

// Create source handlers
var handler = {
canHandleSource: function(source){
return 'probably';
},
handleSource: function(s, t){return {};}
};

Tech.registerSourceHandler(handler);

// Pass a source through the source handler process of a tech instance
tech.setSource(sourceA);

// Test that currentSource_ is not immediately specified
deepEqual(tech.currentSource_, {src:''}, 'sourceA was not stored immediately');

this.clock.tick(1);

// Test that currentSource_ is specified after yielding to the event loop
strictEqual(tech.currentSource_, sourceA, 'sourceA was handled and stored');

// Pass a source with an empty src
tech.setSource(sourceB);

// Test that currentSource_ is not immediately changed
strictEqual(tech.currentSource_, sourceA, 'sourceB was not stored immediately');

this.clock.tick(1);

// Test that currentSource_ is still unchanged
strictEqual(tech.currentSource_, sourceA, 'sourceB was not stored if equal to the empty string');
});
});