Is there a good way to detect if a client browser allows inline media playback for HTML5 video?
Update
I am not trying to simply detect video support.
I am trying to detect if a video can only play fullscreen or also inline. Because on the iPhone safari iOS videos only play in fullscreen, but on iPad videos may be played inline. And by inline I mean in the page without switching to fullscreen.
In iOS10 you can now have a video play inline if the playsinline attribute is added to the video tag.
You can detect this with ('playsInline' in document.createElement('video')).
However this isn't sufficient because this won't exist on desktop browsers - where obviously playing inline is a standard feature.
So this is what I came up with : If not iPhone / iPad then we just assume video can be played inline (this may fail for certain android devices). Otherwise run the test above to check for iOS10
Here is my Modernizr test.
Modernizr.addTest('inpagevideo', function ()
{
return navigator.userAgent.match(/(iPhone|iPod)/g) ? ('playsInline' in document.createElement('video')) : true;
});
Whereas the document iOS-Specific Considerations says:
Currently, Safari optimizes video presentation for the smaller screen
on iPhone or iPod touch by playing video using the full screen—video
controls appear when the screen is touched, and the video is scaled to
fit the screen in portrait or landscape mode. Video is not presented
within the webpage. The height and width attributes affect only the
space allotted on the webpage, and the controls attribute is ignored.
This is true only for Safari on devices with small screens. On Mac OS
X, Windows, and iPad, Safari plays video inline, embedded in the
webpage.
iOS
var videoIsFullscreen = screen.width < 320 &&
navigator.userAgent.indexOf("Safari") > -1 &&
navigator.userAgent.indexOf("Chrome") == -1 &&
navigator.userAgent.match(/(iPhone|iPod)/);
Note that im not sure if small screen is of 320px, you should adjust this value.
EDIT
Take a look at this post.
Summarizing:
var isSmallScreen = screen.width <= 320;
/// the shadows here
var isWideScreen = screen.width >= 568;
After all, I found this post that may help you much
Can I avoid the native fullscreen video player with HTML5 on iPhone or android?
ANDROID
How to play inline html5 video in Android Browser
Note that is for native Android Browser not for Android Chrome.
Starting from iOS 10 video fullscreen option will be available for phones as well, when adding attribute playsinline to video element.
For earlier versions webkit-playsinline can be used, but it will only be respected on iPhones when page is pinned to home screen.
<video webkit-playsinline playsinline></video>
To detect whether inline playback is available canplay event listener can be used, to check whether video is in full screen. If phone doesn't support inline playback it will go straight to fullscreen when starting playback.
var inlinePlaybackSupported = true;
var elem = document.querySelector('video');
elem.addEventListener('canplay', function () {
//if in fullscreen here, then inline playback is not supported;
if (elem.webkitDisplayingFullscreen) {
inlinePlaybackSupported = false;
}
});
The solution I'm using is this:
var video = document.createElement( 'video' );
...
video.addEventListener( 'playing', function () {
// Note: we are adding event listener for 'playing' event, not for 'play' event!
if ( video.webkitDisplayingFullscreen ) {
console.log( 'Inline playback is not supported' );
} else {
console.log( 'Inline playback is supported' );
}
}, false );
Now there is obviously a problem with this aproach: you don't know whether inline is supported or not until after the video has started playing. Also, the event may trigger multiple times if the user pauses the video (not really a problem, but you have to be careful).
I've tested this on iPod touch, iPhone, iPad, Nexus 5 and Htc One X. It provides correct resulsts on all of this deivces.
I don't know if it's going to work on android devices that play video in fullscreen by default. Personally, I've never saw an android device that plays video in fullscreen. But running my method on nexus 5 gives an interesting console log message:
'HTMLVideoElement.webkitDisplayingFullscreen' is deprecated. Please use the 'fullscreenchange' and 'webkitfullscreenchange' events instead.
So I presume that for android you'll have to use something like that:
video.addEventListener( 'webkitfullscreenchange', function ( e ) {
if ( document.webkitIsFullScreen ) {
console.log( 'Inline playback is not supported' );
} else {
console.log( 'Inline playback is supported' );
}
}, false );
but personally, I never saw this event being fired. Neither on android, nor on iOS.
Some other things that I've tested on several iOS devices that DOESN'T WORK:
property video.webkitSupportsFullscreen - always returns false
events 'webkitendfullscreen' and 'webkitenterfullscreen' - these are the funny ones - webkitendfullscreen works just fine, but webkitenterfullscreen never gets fired
ADDED:
I actually managed to find an android device that only shows video in fullscreen (Fly IQ245 Plus). Although its behavior is very similar to that of iOS, I was unable to detect fullscreen change by any means mentioned above.
Related
I have a website set-up, where the background is a YouTube video using Tubular.js plugin. There is a problem with chrome browsers, that auto pauses the youtube video if I load it with mute: false flag. Chrome is the only offender, as it works with opera, firefox etc. If I change the flag to mute: true the video will atuplay fine.
Chrome recently started to block atuplayed videos with sound. Is there an option to bypass this on chrome, or at least modify the tubular.js library/js call so that it will only mute (regardless of settings) on chrome user-agents?
https://codepen.io/anon/pen/MGEZrO
Thanks in advance
According to chrome logic it is impossible to autoplay video if it is NOT muted. However they allow to autoplay video if it is muted and WILL NOT stop it if user will unmute it. By this (user interaction) chrome means just a single tap OR click by the user on the website (everywhere, not video components only).
Just make your user to make a single click on your webpage and THEN you can mount/start video with autoplay and sound.
I have the similar situation with my react spa. And I force my user to make a single click before mounting the video. Only this way it starts to play with sound.
I also had the situation where the video MUST have started even without click and the I just addEventListener on whole page to unmute it as soon as possible
play(from = null) {
document.addEventListener('click', () => {
// any click will force my video to unmute
this.player.muted = false;
});
// rest code for updating state etc
}
Unfortunately, triggering click is not working (the video will stop automatically)
According to their guidelines about autoplay on chrome ;
Unfortunately, Chrome cannot provide any whitelist exceptions to the autoplay policy.
They also explain how to present the content in a less-invasive way (muted video first) and some other tips about the policy.
My website play sound on some events. Everywhere it is working fine but not on Safari browser.
Found that safari adds my website to the auto-play blocked list. I want to change the default value from stop playing to allow playing, using javascript.
Thanks in advance.
It's a feature implemented for user convenience and comfort in Safari 11 and onwards to stop sites from auto-playing ads or interrupting the users.
I think you probably can't bypass it. Instead, detect if your visitors are using Safari by,
var isSafari = /constructor/i.test(window.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window['safari'] || (typeof safari !== 'undefined' && safari.pushNotification));
and display a popup explaining to them how they can enable auto-playing media on your website.
Thats a nightmare. Im currently working on a auto-play feature and not only safari but also chrome 64 mobile dont support autoplay. The only thing you can do to work around this, is by adding the muted attribute to the video tag, that should work.
I've spent way too many hours on this with very little success. We have a client with a site that has a YouTube video popup when the page loads. It autoplays on desktop and shows the Youtube play button on mobile since autoplay is not supported on mobile. I am using the iFrame JS API to instantiate the video player (code examples below). This setup is working perfectly on desktop, but on mobile devices (Android or iOS), between myself and my coworkers, clicking the Youtube play button only plays the video about 80% of the time. The rest of the time the video loading spinner just spins and nothing happens. If I close a reload the player using the site controls it will play, but not initially.
I know that this will not be an issue for the majority of users viewing the site but I know our client is going to go ape crazy if, out of 100 reloads on their iPhones, even 10 of them result in this behavior.
I am instantiating the player as follows:
1) I am including a "hard copy" of the Youtube iframe api JS on the site first.
2) I have an object controlling the display of the youtube "modal" window that contains the player target -- when the function is called it does the following:
// Write a div element to the container
_instance.videoContainer.innerHTML = '<div id="youtube-player"></div>';
// Grab a reference to it
_instance.el = document.getElementById('youtube-player');
// Call the YT player API
_instance.player = new YT.Player('youtube-player', {
playerVars: { // trying a bunch of different params with no success
playsinline : 1 ,
origin : window.location.origin ,
autoplay : 1 ,
wmode: "opaque" ,
iv_load_policy : 3
},
videoId: videoId , // This is passed to the function
events : {
onReady : function(){
console.log('resolved player');
// another function that just changes the container visibility
_instance.play();
},
onStateChange : function( event ){
if( event.data == YT.PlayerState.ENDED ){
_instance.close();
}
}
}
});
At this point, the video is either playing automatically in desktop 100% of the time, or it has shown the Youtube player with the video thumbnail and big red play button on mobile. This is where the trouble starts -- most of the time it plays fine, the rest of the time it just spins and spins and never plays. What's interesting is, on Android, if I blur the window and reopen it, I can click the play button again and it will play.
It shouldn't matter at this point, but I am destroying the div and the player reference when the modal is closed.
I've tried pretty much everything I can think of...
The Youtube video is somehow being throttled and only showing so many times through the iframe to the origin? I added the 'origin' property to the params thinking this might be the case, but it didn't seem to make much of a difference. I seem to have a higher success rate than my coworkers loading the video.
Is there some reason to asynchronously load the youtube iframe script as in the examples, rather than loading a copy from my site?
That's all I can think of at this point... is there something I'm missing? Thanks.
There is a related thread which stated that the autoplay function is not allowed for most mobile devices.
From this documentation:
Due to this restriction, functions and parameters such as autoplay, playVideo(), loadVideoById() won't work in all mobile environments.
A simple workaround is to have a custom looks of the "play" button:
Have an overlay element with pointer-events: none;. pointer-events works on all modern mobile browsers or simply have the video container over the button with opacity: 0.
Hope this helps!
I ran into the almost the same exact problem. For us it was specific to cellular connections.
If the embed is larger than ~360px wide, the player attempts to serve up quality at "large" or higher to which AT&T and Verizon are throttling.
The result we see: player enters buffering state and cannot achieve playback.
Tests over T-Mobile work OK without issue.
Players embedded at or below 360px wide play OK on all networks at quality of "medium" or lower.
Hello guys I have got custom fullscreen icon that triggers fullscreen on my video. Everything is ok except that it doesn't work on Apple's devices. Do you know how to fix that?
$('.fullscreen_btn').click(function() {
fullscreen=true;
var mediaElement = document.getElementById('videoAbout');
if(mediaElement.requestFullScreen) {
mediaElement.requestFullScreen();
}
else if(mediaElement.webkitRequestFullScreen) {
mediaElement.webkitRequestFullScreen();
}
else if(mediaElement.mozRequestFullScreen) {
mediaElement.mozRequestFullScreen();
}
else if(mediaElement.msRequestFullScreen) {
mediaElement.mozRequestFullScreen();
}
});
As I said - code above is working on Windows/android devices, but not on Apple's.
I sloved my question. All i had to do is that:
var mediaElement = document.getElementById('videoAbout');
mediaElement.webkitEnterFullscreen();
mediaElement.enterFullscreen();
This is opening fullscreen on HTML5 video on iOS devices.
Quoting directly from the website
In Safari, the built-in video controls include a play/pause button, volume control, and a time scrubber. In Safari 5.0 and later on the desktop and on iOS 4.2 on the iPad, the controls also include a full-screen playback toggle on the lower right. The controls automatically fade out when the video is playing and fade in when the user hovers over the video or touches it.
I also says If you embed audio or video in your website, you should use HTML5. you might be using old html4, I don't know. Try this link
I have a scenario where I have search results that contain video content. Each video item in the results has a thumbnail sized video player, so up to 10 html 5 video players can exist per result set. When the user clicks the thumbnail, the video goes fullscreen and automatically plays the video. When the user exits fullscreen, the video pauses.
This all works great on iOS devices, but on android I have significantly more even handling to worry about. Here's the logic as I have it now:
goFullScreen: function (ev) {
var el = ev.target,
isVideoFullscreen = el.webkitDisplayingFullscreen;
el.webkitEnterFullScreen();
// the approach below is the only way I could get reliable fullscreen detection on android
$(window).bind("resize", function (e) {
if (isVideoFullscreen != el.webkitDisplayingFullscreen) {
isVideoFullscreen = el.webkitDisplayingFullscreen;
if (isVideoFullscreen) {
el.load();
el.play();
} else {
el.pause();
}
}
});
}
Even though iOS does not need all of this even handling, it still works fine. The problem with android is that when I exit fullscreen, the video pauses, but the poster image is replaced for the video I just paused with a still from the video (to be expected), but all subsequent videos in the result set have their poster image replaced with an ugly video icon. As a result, the thumbnails just look like broken videos. But if you tap them they still go fullscreen and play just fine.
I'm testing on a Galaxy Nexus and a Galaxy SII. I can say that the el.pause() is not responsible, if removed the video will continue playing in the thumbnail and all video tags below it will still have the broken poster icon.
This works as expected on desktop webkit browser and on iOS devices. Only experiencing this issue on android 4+ devices. Also remember that the EnterFullscreen request has to happen in the scope it's in. Calling out of this scope will prevent it from working due to security restrictions on mobile devices. I've pretty much exhausted all ideas so I'm looking here to hopefully get a few more.
Any suggestions would be greatly appreciated.
I've given up on trying to solve all of the bugs and quirks in Android. Instead, I'm just linking directly to the mpeg4 videos from the thumbnails. So no more video tags, no more event handling.
The only side effect is that some versions of android display a dialog on how you want to play the video, which is not ideal but better than any alternative I could find. Fortunately the iOS experience is consistent no matter what approach I take.