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

Monkeypatch canPlayType on Android 4.0+ for HLS #1084

Merged
merged 14 commits into from
Mar 26, 2014
Merged

Conversation

gkatsev
Copy link
Member

@gkatsev gkatsev commented Mar 13, 2014

Android devices starting with 4.0 can play HLS natively to some extent.
However, they do not say so in the canPlayType method. This commit
monkey patches canPlayType to respond with "maybe" for
"application/x-mpegURL" and "application/vnd.apple.mpegURL". Otherwise,
it'll fallback to the original canPlayType method.

Caveat, HLS on android is somewhat broken. In my test streams, it doesn't have a duration so you can't seek.

This fixes videojs/videojs-contrib-hls#29

Android devices starting with 4.0 can play HLS natively to some extent.
However, they do not say so in the canPlayType method. This commit
monkey patches canPlayType to respond with "maybe" for
"application/x-mpegURL" and "application/vnd.apple.mpegURL". Otherwise,
it'll fallback to the original canPlayType method.
var canPlayType = HTMLVideoElement.prototype.canPlayType;

HTMLVideoElement.prototype.canPlayType = function(type) {
if (type && type === 'application/x-mpegURL' || type === 'application/vnd.apple.mpegURL') {
Copy link
Member

Choose a reason for hiding this comment

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

I was called out on this one... I think this should technically be a case-insensitive match.

Copy link
Member Author

Choose a reason for hiding this comment

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

Not only that but the official mimetype is all lowercase: http://tools.ietf.org/html/draft-pantos-http-live-streaming-12#section-10

Copy link
Member Author

Choose a reason for hiding this comment

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

Changed.

@heff
Copy link
Member

heff commented Mar 17, 2014

Would it make sense to combine this with the following function? Also, want to write a test for this?

@gkatsev
Copy link
Member Author

gkatsev commented Mar 17, 2014

Looks like it's a bit tricky to write a test for this as it is right now.
Only way I can think of right now is to add another HTML file that sets the useragent to be android before loading the specific test for this.

patchCanPlayType is called on load.
It patched video#canPlayType if needed.
unpatchCanPlayType will revert the patch and return the patch function.
There are also corresponding tests that test patchCanPlayType,
unpatchCanPlayType and also whether the patch functions themselves work
correctly.
@gkatsev
Copy link
Member Author

gkatsev commented Mar 18, 2014

Reworked the monkeypatching to use a patch and unpatch methods. This, not only allows us to remove the patching if needed, but it also facilitates better testing.

@heff
Copy link
Member

heff commented Mar 24, 2014

Double quotes are making the tests fail.

@gkatsev
Copy link
Member Author

gkatsev commented Mar 24, 2014

Fixed up jshint errors.

@gkatsev
Copy link
Member Author

gkatsev commented Mar 24, 2014

I dont know why it's failing...

(function() {
var canPlayType,
mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl$/i,
mp4RE = /^video\/mp4$/i;
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we want the end-of-line character here, in case codec info is included.

Copy link
Member Author

Choose a reason for hiding this comment

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

done.

@@ -1,5 +1,7 @@
module('HTML5');

var oldAndroidVersion;
Copy link
Member

Choose a reason for hiding this comment

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

not used anymore?

patchCanPlayType = video.canPlayType;
unpatchedCanPlayType = vjs.Html5.unpatchCanPlayType();

strictEqual(video.canPlayType, vjs.TEST_VID.constructor.prototype.canPlayType, 'original canPlayType and unpatched canPlayType should be equal');
Copy link
Member

Choose a reason for hiding this comment

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

Aren't these two references the same the same thing always?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep. I'll see if I can figure out what I meant to refactor this into.

@heff heff closed this Mar 26, 2014
@heff heff reopened this Mar 26, 2014
Fix up tests to not ignore some if canPlayType is not available since
unpatch is no longer broken.
@heff
Copy link
Member

heff commented Mar 26, 2014

great stuff, thanks!

@heff heff merged commit e39557e into videojs:master Mar 26, 2014
@gkatsev gkatsev deleted the monkeyhls branch March 26, 2014 21:41
@@ -38,3 +38,59 @@ test('should re-link the player if the tech is moved', function(){

strictEqual(player, tech.el()['player']);
});

test('patchCanPlayType and unpatchCanPlayType are available on Html5 object', function() {
Copy link
Member

Choose a reason for hiding this comment

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

@gkatsev are these meant to check that the functions exist after minifying?

Copy link
Member Author

Choose a reason for hiding this comment

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

um... yes. Though, I guess would we want to check that it as a string so it doesn't get minified since we want those functions exported?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I typically do that in the api.js file, though I guess a string key would do the same thing

Copy link
Member Author

Choose a reason for hiding this comment

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

We could move this test there if you think it would be a better place for them.

@krzysztofantczak
Copy link

It doesn't seem to help under android 4.0.3 which plays m3u8 natively very well but videojs throws on me with 'No compatible source was found for this video'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Android devices that support HLS don't switch to native implementation but fail to play instead
5 participants