Detect model of iOS device using Javascript or HTML? - javascript

So I'm serving H.264 .mp4 video on my website. I'm using open source HTML5 video player http://mediaelementjs.com/. Some visitors are viewing from Safari for iPhone. The iPhone 4 supports video playback only up to 720p, so if I make my videos smaller than that, they work on the 4 and the 4S. But the 4S supports video up to 1080p. So how would I serve a larger video to the 4S and a smaller video to the 4? I tried this:
<video width="640" height="400" id="player" controls="controls" preload="auto">
<source src="https://s3.amazonaws.com/my-big-1080p-video.mp4" type="video/mp4">
<source src="https://s3.amazonaws.com/my-small-720p-video.mp4" type="video/mp4">
</video>
But it didn't work. The iPhone 4 isn't smart enough to try the second source. How can I make my website serve the correct video to the different devices?

Play 720p video on iPhone 4 — 1080p video on iPhone 4S
Try this on an iPhone 4 and a 4S (jsfiddle)
<video src="http://file.brow.sr/1080p.mp4" onerror="this.src='http://file.brow.sr/720p.mp4';" controls loop width="320" height="180">
</video>
Explanation
Load the 1080p video, then use Javascript's onError to fall back to 720p.
Safari will sniff the header of the 1080p file to determine if it's playable, and if it's too big to decode it will throw an error. We then catch that error to provide the 720p video.
By using this kind of feature detection, the fallback will not only work on one device (iPhone 4) but probably on a lot of different capable browsers.
Why multiple <source>'s won't work
When using multiple <source> tags with the same MIME types, the browser will load the first source that has a compatible MIME type and discard the others, even if that video is not playable. That's because source elements are expected to provide alternative video codecs (eg. ogg, webm, mp4), not alternative frame sizes / file sizes.

Here is how to go about it:
1) Retrieve the device model by using wurfl
<script type='text/javascript' src=“//wurfl.io/wurfl.js"></script>
You can either use HTTP or HTTPS (both are are supported) If you plan to use the device information provided by the script to make rendering decisions, then you might want to include the script in the element. Otherwise, you can load it asynchronously. Now you have access to the WURFL object within JavaScript.
Sample response looks something like:
{ complete_device_name:"Apple iPhone 5", form_factor:"Smartphone",
is_mobile:true }
off course you can(and should)
console.log(WURFL);
to find out the rest of the properties you can use.
2) Now that you know which exactly which device model your users are
on, you can switch the video players configs.
How about something like?
<video width="IPHONE5_VIDEO_WIDTH"
height="IPHONE5_VIDEO_HEIGHT"
id="player" controls="controls"
preload="auto">
<source src="IPHONE5_VIDEO_URL" type="video/mp4">
</video>
super clean and readable right?
Hope that helps.

I have a php script that does this. I got it here - http://detectmobilebrowsers.com/ - and yes, there is a javascript, JQuery, etc. versions. It's worked quite well for us and it has the benefit of seeming to stay fairly updated. The only issue we've run into was an iPad that had been deliberate set not to identify itself as a mobile device.

Your solution don't work because of the reason mentioned by dear #Duvrai.
I've searched to attain a right way to meet your purpose and it seemed we have no choice unless using some javascript code (here without considering server side programming) to make a decision which source should be delivered. The bellow snippet detects the browser Type and its Version:
navigator.sayswho= (function(){
var ua= navigator.userAgent, tem,
M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if(/trident/i.test(M[1])){
tem= /\brv[ :]+(\d+)/g.exec(ua) || [];
alert('IE '+(tem[1] || ''));
}
if(M[1]=== 'Chrome'){
tem= ua.match(/\bOPR\/(\d+)/)
if(tem!= null) alert('Opera '+tem[1]);
}
M= M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
if((tem= ua.match(/version\/(\d+)/i))!= null) M.splice(1, 1, tem[1]);
alert( M.join(' '));
})();
Now you can write some lines of code in javascript and decide to change video sources based on browser Type and Version.

Try this link
The library should be able to detect user-agent and you can serve appropriate files accordingly.

I cannot offer sample code since I am not an Apple geek, but I can tell you based off of my experience trying to make sites compatible between XHTML and HTML5 that it is better to check for browser capability than browser version.
The reason for this is that there are too many browser versions to justify the upkeep, and also the user agent string can be modified. I recommend that you write a script that checks for HTML5 video capabilities with a simple if statement, and then render either one video or the other depending upon the results.

A mobile device detection database like WURFL (Wireless Universal Resource File - http://wurfl.sourceforge.net/) or DeviceAtlas may be overkill if video is the only capability you're checking for. But it is a quick way to get robust capabilities detection for a vastly larger range of devices than you would be able to feasibly compile checks for, and would come in handy if your site ever needs to verify other capabilities besides video support.

MEJS player does not handle errors correctly, I'd to add more support to be able to detect what actually happened. On iPhone it even sometimes throws an error event but there is no actual error and you can play the video correctly.
Open mediaelement-and-player.js and look for
// error handling
media.addEventListener('error',function() {
loading.hide();
controls.find('.mejs-time-buffering').hide();
error.show();
error.find('mejs-overlay-error').html("Error loading this resource");
}, false);
Then use this code:
// error handling
media.addEventListener('error',function() {
var
videoError = error.closest('.mejs-inner').find('video,audio')[0].error,
msg = 'Error loading this resource.';
if (!videoError) { //webkit sometimes throws error event but video has no actual error and can play the video correctly - ignore the event
console.log('MEJS event: error throws but no error found - ignored');
return;
}
//hide elements visible while loading and playing - cannot play after error
loading.hide();
controls.addClass('hidden'); //controls are automatically displayed when mouse hover is detected - must hide it permanently using class with !important
error.closest('.mejs-inner').find('.mejs-overlay-play').hide(); //also hide overlay with play button
error.show();
//get relevant error message
switch(videoError.code) { //see http://www.w3.org/TR/html5/embedded-content-0.html#error-codes
case videoError.MEDIA_ERR_ABORTED: //loading stopped (by user, e.g. by pressing ESC or Back)
msg = 'Video loading aborted';
break;
case videoError.MEDIA_ERR_DECODE: //invalid format (actually presumed format is OK, but the data does not correspond with the defined format - probably corrupted file of data transfer)
msg = 'Video file is broken';
break;
case videoError.MEDIA_ERR_NETWORK: //network problem (was able to connect to the provided URL but could not get the video data)
msg = 'Network connection lost';
break;
case videoError.MEDIA_ERR_SRC_NOT_SUPPORTED: //invalid source URL (url provided does not lead to a supported video file)
msg = 'Video not supported';
break;
}
//display error
console.log('Video error: ' + msg + ', code: ' + videoError.code);
error.find('.mejs-overlay-error').html(msg);
}, false);
If you need to you can add your own handling that will switch to 720p in case of unsupported video.
And in mediaelementplayer.css add this (not sure if actually required or just improvement for my theme):
/* Display errors */
.mejs-overlay-error {
color: white;
background: black;
text-align: center;
font-size: 1.2EM;
}
.mejs-controls.hidden {
display: none !important;
}
/* End: Display errors */
This is for version 2.13.1, not sure if newer version is better.
Update: newest version 2.16.3 contains exactly same useless error handler.

This will detect the iOS version. Maybe it can be useful:
if (navigator.userAgent.indexOf('5_0') != -1) {
alert('IOS 5');
} else {
alert('Other');
}
Edit:
I have have ajusted and tested the script.

Put this in your tags:
<meta name="viewport" content="initial-scale=1.0">
<meta name="viewport" content="width=320.1">
<script>
if (window.screen.height==568) { // iPhone 5
document.querySelector("meta[name=viewport]").content="width=320.1";
// your code here
}
</script>

I use this code:
// iPhone 3
if (window.screen.height==480 && window.screen.width==320 && window.devicePixelRatio==1)
{
$('#chartDivWrapper').html('<div id="chartdiv" style="height:300px;width:500px;"></div>');
}
// iPhone 4, this is Retina
else if (window.screen.height==480 && window.screen.width==320 && window.devicePixelRatio==2)
{
$('#chartDivWrapper').html('<div id="chartdiv" style="height:300px;width:500px;"></div>');
}
// iPhone 5
else if (window.screen.height==568 && window.screen.width==320 && window.devicePixelRatio==2)
{
$('#chartDivWrapper').html('<div id="chartdiv" style="height:400px;width:600px;"></div>');
}
// iPad
else if (window.screen.height==1024 && window.screen.width==768 && window.devicePixelRatio==1)
{
$('#chartDivWrapper').html('<div id="chartdiv" style="height:425px;width:680px;"></div>');
}
// iPad Retina
else if (window.screen.height==1024 && window.screen.width==768 && window.devicePixelRatio==2)
{
$('#chartDivWrapper').html('<div id="chartdiv" style="height:425px;width:680px;"></div>');
}
// all other, this was before for all
else
{
$('#chartDivWrapper').html('<div id="chartdiv" style="height:400px;width:600px;"></div>');
}

Related

HD control for HTML5 video

I have set up an Html5 video and it has the basic controls. However, the video I uploaded is quite heavy and I would like to give a lower resolution option, like an HD switch control. I looked on the internet on how to apply an HD button to html5 but the primary solution seems to install a video player. Is there a simpler way to implement an HD button without needing to install the video player? I already set up my html5 video with several jQuery commands and I would not like to go through the effort of starting from scratch again. I also looked that one could customise the html5 video controls as well. Would one be able to set up a customised HD button through html/javascript only? If yes, how one does it?
Here's the code I have at the moment
<video src="../Frustrated/Frustrated.mp4" controls preload="metadata"> <source src="../Frustrated/Frustrated.mp4" type="video/mp4">
you could probably make this look a lot more elegant, but the code sample below will allow you to have buttons which change the source between HD and regular versions (based on the ID of the button, but you can change the logic if needed). The code also checks to see if the browser supports mp4, ogg or webm and defaults to the first supported format (so you'd potentially need encodes for each type if you make use of that part of the code
<video width="400" controls id="video">
<source src="../Frustrated/furstrated.mp4" type="video/mp4">
Your browser does not support HTML5 video.
</video>
<br>
<button id="frustratedHD" onclick="playvid(this)">HD</button><button id="frustrated" onclick="playvid(this)">Regular</button>
<script>
// gets the video element
var video = document.getElementById("video");
// sets the extension / container we'll use
var vidType = "";
// identifies what type of video we can play, assuming this is an HTML5 supporting browser
if (video.canPlayType) {
if (video.canPlayType('video/mp4; codecs="avc1.42E01E"') == "probably") {
vidType = "mp4"
} else {
if (video.canPlayType('video/ogg; codecs="theora"') == "probably") {
vidType = "ogg"
} else { if (video.canPlayType('video/webm; codecs="vp8, vorbis"') == "probably") {
vidType = "webm"
}
}
}
}
// you'll want to decide how to handle no supported video type...
function playvid(vid) {
// log selected item to confirm selection, can comment this line out
console.log("../Frustrated/" + vid.id + "." + vidType)
// set the video element source to selected content and correct type
video.src = "../Frustrated/" + vid.id + "." + vidType
video.play();
}
</script>
Upload the video in different qualities to your server, and play a different video depending on the quality the user has chosen.
Even if it's possible to downgrade a video on the client side, it's pointless, because the client still has to download the HD video in order to convert it.

Is there any possibility to control HTML5 audio volume on IOS?

I use the html5 audio library Buzz to add sounds to a browser game. There is a toggle button to mute and unmute sound, which works good on desktop and Android devices. Unfortunately it seems like the audio tag is quite limited on IOS, so that I cannot mute audio in Mobile Safari (see https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Introduction/Introduction.html):
On iOS devices, the audio level is always under the user’s physical control. The volume property is not settable in JavaScript. Reading the volume property always returns 1.
Do you know any workaround to control volume of html5 audio tags in Mobile Safari?
To add volume change support to iOS and not rewrite your entire app from html5 audio to web audio for that, you can combine these audio solutions via createMediaElementSource.
Please see more details at Mozilla website https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/createMediaElementSource
I always thought dynamic volume control and certainly crossfading, as we all know, is impossible. Apple has dictated that it be so. Except.... apparently the folk at Kodo Games (specifically Nicola Hibbert?) have pulled it off and made the code available to anyone. I just checked it on iOS 8. Fading and crossfading seem to work!
Check it out (new site that works): Getting Started with Web Audio API
It seems that you can set the muted property instead of updating the volume value. Works on iOS 15
/**
* Set volume of sound object
* #param volume
*/
setVolume (volume) {
const muted = volume === 0
// iOS workaround when volume is 0
this.sound.muted = muted
this.sound.volume = volume
}
I worked around this by simply stopping all sounds and setting a variable isMuted to true or false, so I can check this everywhere a sound is played:
// set the variable
var isMuted = false;
// toggle audio
function toggleMute() {
var toggleAudioBtn = $(".toggleAudio");
if (isMuted == false) {
sounds.stop();
isMuted = true;
toggleAudioBtn.css("background-image", "url('images/ui/btn_audio_mute.png')");
} else {
isMuted = false;
toggleAudioBtn.css("background-image", "url('images/ui/btn_audio.png')");
}
};
// for every sound check if sound is muted
if(isMuted == false) {
sound.play();
}

navigator.userAgent to detect for mobile device?

Many people use the following to detect for iPad or iPhone.
<script>
var agent=navigator.userAgent.toLowerCase();
var useHTML5 = (agent.indexOf('iphone')!=-1 || agent.indexOf('ipad')!=-1);
if (useHTML5){
document.write("");
} else{
document.write("");
}
</script>
The Apple official way to detect only for ipad iphone is
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// iPad-specific code
} else {
// iPhone-specific code
}
But what if I also want to check for other mobile(at least Android devices anyways)?
Should I resort to Modernizr?
Or a script from
http://detectmobilebrowsers.com/ ?
Just want to add that in my particular case am using FancyBox with VideoJS.
MobileESP Project has a solid array of user-agent detecting methods in JavaScript too yet MobileESP API: JavaScript is very limited simply because some devices has no JavaScript support and a server side detection is the right way to do it. DeviceAtlas Products will provide more information about the device capabilities if needed yet has its price tag too...

Event Listeners in HTML5 Video on the iPad Safari not working?

I've got this in the <head>:
<script>
function log(event){
var Url = "./log.php?session=<?php echo session_id(); ?>&event=" + event;
xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", Url, true );
xmlHttp.send( null );
}
</script>
And this in the <body>:
<video id="video" src="./video/LarryVideo.mp4"
controls="controls"
poster="./img/video_poster.jpg"
onabort="log('onabort');"
oncanplay="log('oncanplay');"
oncanplaythrough="log('oncanplaythrough');"
ondurationchange="log('ondurationchange');"
onemptied="log('onemptied');"
onended="log('onended');"
onerror="log('onerror');"
onloadeddata="log('onloadeddata');"
onloadedmetadata="log('onloadedmetadata');"
onloadstart="log('onloadstart');"
onpause="log('onpause');"
onplay="log('onplay');"
onplaying="log('onplaying');"
onprogress="log('onprogress');"
onratechange="log('onratechange');"
onreadystatechange="log('onreadystatechange');"
onseeked="log('onseeked');"
onseeking="log('onseeking');"
onstalled="log('onstalled');"
onsuspend="log('onsuspend');"
ontimeupdate="log('ontimeupdate');"
onvolumechange="log('onvolumechange');"
onwaiting="log('onwaiting');">
<script>
QT_WriteOBJECT('./video/LarryVideo.mp4',
'380px', '285px', // width & height
'', // required version of the ActiveX control, we're OK with the default value
'scale', 'tofit', // scale to fit element size exactly so resizing works
'emb#id', 'video_embed', // ID for embed tag only
'obj#id', 'video_obj'); // ID for object tag only
</script>
</video>
My normal Safari creates nice log-file entries as expected. Mobile Safari from iPad however doesn't do anything at all.
What could be wrong with this?
I have not been able to get a hold of readystate on an ipad either, but you can get other events that more-or-less let you infer the readystate.
var audio = new Audio("someSource.mp3");
audio.play();
/* you may need to use .load() depending on how the event was initiated */
audio.addEventListener("canplay", handleCanPlay, false);
audio.addEventListener("durationchange", handleDurationChange, false);
But let's be clear, the problem is Apple pretty much telling the whole world they're using the internet wrong. Granted, everyone hates sites that start playing music the second they load, but then Apple goes nuts and kills ANY/ALL buffering of audio/video that isn't explicitly initiated by a user gesture because Apple, apparently, thinks their users can't hit "back" if a site bothers them; fanboys agree too. This basically leaves the rest of us to hack up our applications if we dare try and manage any kind of sound effects. I know this isn't the place to rant, but building ANY soft of interesting/interactive experience in HTML5 on the iPad is one facepalm after another -- be it the 5mb cache limit that simply crashes the browser if a page has "too" many (according to Apple) images, or the difficulty to preload any sort of media to enhance UI. Seriously, outside of Wordpress blogs and RSS readers, mobile Safari's implementation of HTML5 is pretty worthless. And so the dream of HTML5 "build once, play anywhere" value proposition is dead and we go back to developing native apps. At least this gives us good job security! /rant

Is there a documented JavaScript API for Windows Media Player?

I want to use JavaScript to control an embedded Windows Media Player, as well as access any properties that the player exposes. I've found a few hacky examples online, but nothing concrete.
I really need access to play, pause, stop, seek, fullscreen, etc. I'd also like to have access to any events the player happens to broadcast.
Help would be wonderful (I already have a Flash equiv, just so you know), thanks!
The API requires ActiveX connectivity native to Internet Explorer, or can use a plugin for Firefox.
Here's a sample page that might get you started.
<html>
<head>
<title>so-wmp</title>
<script>
onload=function() {
player = document.getElementById("wmp");
player.URL = "test.mp3";
};
function add(text) {
document.body
.appendChild(document.createElement("div"))
.appendChild(document.createTextNode(text));
};
function handler(type) {
var a = arguments;
add(type +" = "+ PlayStates[a[1]]);
};
// http://msdn.microsoft.com/en-us/library/bb249361(VS.85).aspx
var PlayStates = {
0: "Undefined", // Windows Media Player is in an undefined state.
1: "Stopped", // Playback of the current media item is stopped.
2: "Paused", // Playback of the current media item is paused. When a media item is paused, resuming playback begins from the same location.
3: "Playing", // The current media item is playing.
4: "ScanForward", // The current media item is fast forwarding.
5: "ScanReverse", // The current media item is fast rewinding.
6: "Buffering", // The current media item is getting additional data from the server.
7: "Waiting", // Connection is established, but the server is not sending data. Waiting for session to begin.
8: "MediaEnded", // Media item has completed playback.
9: "Transitioning", // Preparing new media item.
10: "Ready", // Ready to begin playing.
11: "Reconnecting" // Reconnecting to stream.
};
</script>
<script for="wmp" event="PlayStateChange(newState)">
// http://msdn.microsoft.com/en-us/library/bb249362(VS.85).aspx
handler.call(this, "playstatechange", newState);
</script>
</head>
<body>
<div id="page">
<object id="wmp"
classid="clsid:6BF52A52-394A-11d3-B153-00C04F79FAA6"
type="application/x-oleobject">
</object>
</div>
</body>
</html>
There is an API in Microsoft's developer center, but it will only work if you embed windows media player using active-x.
To "learn" more about the API, check out MSDN: http://msdn.microsoft.com/en-us/library/dd564034(VS.85).aspx
Windows media player is exposed as an activex control that any scripting language running in the windows script host should be able to access. You should be able to use jscript to control it. Jscript is microsofts implimentation of java script. For information on what objects and methods are availble using jscript for windows media player se this link.
There is no open JavaScript library as far as I know for crossbrowser clientside handling of a WMP player.
However, this link should make it quite easy for you to start your own little library. The code might need some updating and testing in modern browser versions but you have the basics there.
The library your searching for would be a great idea for a Google Code project, I guess that while everyone today is using Adobe Flash with sIFR / swfobject or Microsoft Silverligt with sistr etc, there are not much interest to write clientside script controlling for WMP.
Should use next WMP object (works in Chrome, FF, Safari)
objPlayer = document.getElementById("wmp");
objPlayer.controls.stop();
objPlayer.URL = this.url;
objPlayer.controls.play();
<EMBED id="wmp" TYPE="application/x-mplayer2" name="MediaPlayer" width="0" height="0" ShowControls="0" ShowStatusBar="0" ShowDisplay="0" autostart="0"></EMBED>

Categories