HTML5 Video & Skinning Tutorial Part 5: Sound
June 28, 2010 by Nicholas DavisonLast Thursday we covered interactive progress bars.
Today we will be covering sound – muting, un-muting and adjusting the volume of our videos.
Throughout these tutorials, we will be continuing the concepts/implementation division: Explaining the ideas first, letting those who wish to run ahead do so – then going over a step by step implantation with jQuery.
Concepts
Property: volume
The .volume property is a floating point value from 0 to 1 that can be both read to find the current value for the player and also written to.
/* Get volume and store it */
var currentVolume=document.getElementById('myVideo').volume;
/* Get volume as a percentage and store it */
var currentVolumePercent=document.getElementById('myVideo').volume*100;
/* Set volume to 50% */
document.getElementById('myVideo').volume=0.5;
Property: muted
.volume alone doesn’t tell you everything. The Boolean .muted, also readable and writeable, controls whether the player is muted, regardless of what the volume is set to.
/* Get muted state and store it */
var isMuted=document.getElementById('myVideo').muted;
/* Mute */
document.getElementById('myVideo').muted=true;
/* Unmute */
document.getElementById('myVideo').muted=false;
Event: volumechange
To detect changes in volume or muting from other sources – such as user interaction via right clicks – you can listen for the volumechange event and then query .volume and .muted.
Implementation
HTML
We start by adding another button, just like all the others.
<li class="video_sound">
<a href="#">Sound</a>
</li>
And then, using it as an anchor point, add a pair of nested divs to act as the volume controls.
<li class="video_sound">
<a href="#">Sound</a>
<div class="video_sound_volume">
<div class="video_sound_volume_bar"></div>
</div>
</li>
CSS
To make further absolute positioning use it as a 0,0 point, we make .video_sound position relative:
.video_sound {
position: relative;
}
We make the .video_sound_volume an absolute positioned, initially hidden (display: none) container.
.video_sound .video_sound_volume {
background-color: black;
border: 1px inset #888;
display: none;
height: 100px;
left: 25px;
position: absolute;
top: -95px;
width: 52px;
Hovering over the parent .video_sound is then set to display .video_sound_volume.
For backwards compatibility with IE6, we would normally use the suckerfish approach. However, as this is for HTML5 video, which IE6 isn’t going to come close to supporting, I’ve left it out.
.video_sound:hover .video_sound_volume {
display: block;
}
Finally, we add the volume bar itself, functioning exactly the same way the progress bar did earlier in the week, just vertically instead of horizontally.
.video_sound .video_sound_volume_bar {
background-color: #00ff00;
height: 50%;
left: 0;
position: absolute;
bottom: 0;
width: 100%;
}
JavaScript
As usual, we start by setting up the general framework we are going to fill in:
function initVideoSound() {
/* For all videos */
$('video').each(function() {
/* Store local references to the controls to avoid having to repeatedly search */
/* Bind the volumechange event for the video */
/* Bind the click event for the sound buttons to mute/unmute */
/* Set the initial values */
});
/* For all video sound volumes */
$('.video_sound_volume').each(function() {
/* Bind click functionality */
});
}
Next we store all of the local references to avoid having to repeatedly search:
/* Store local references to the controls to avoid having to repeatedly search */
var _video=this;
var $_controls=findControlsForVideo(_video);
var $_volume_bars=$_controls.find('.video_sound_volume_bar');
var $_sound_buttons=$_controls.find('.video_sound a');
Next we intercept the volume change events from the video, updating the bar position:
/* Bind the volumechange event for the video */
$(_video).bind('volumechange', function() {
/* Set the height of the volume bars to match the new volume */
$_volume_bars.css("height", (_video.volume*100)+"%");
if (_video.muted) {
$_sound_buttons.removeClass('active');
} else {
$_sound_buttons.addClass('active');
}
});
Then we do the same for the mute/unmute state of the sound button:
/* Bind the click event for the sound buttons to mute/unmute */
$_sound_buttons.bind('click', function(e) {
e.preventDefault();
if (_video.muted) {
_video.muted=false;
} else {
_video.muted=true;
}
});
And we set the initial states of the volume slide and mute buttons:
/* Set the initial values */
$_volume_bars.css("height", (_video.volume*100)+"%");
if (_video.muted) {
$_sound_buttons.removeClass('active');
} else {
$_sound_buttons.addClass('active');
}
Finally, in much the same way we did with the progress slider, we bind click interaction for the volume sliders:
/* For all video sound volumes */
$('.video_sound_volume').each(function() {
/* Store local references to the video to avoid having to repeatedly search */
var $_video=findVideoForElement(this);
/* Bind click functionality */
$(this).click(function(e) {
/* Calculate the decimal percentage (0-1.0) of the way up the bar the event happened at
then invert it as the bar is relative to the bottom, not the top. */
var _position=findEventPositionWithinElement(e);
var _decimal=1-(_position.top/$(this).height());
/* For all of the videos */
$_video.each(function(index, _video) {
/* Set the new volume */
_video.volume=_decimal;
});
});
});
This gives us a complete initSound() function of:
function initVideoSound() {
/* For all videos */
$('video').each(function() {
/* Store local references to the controls to avoid having to repeatedly search */
var _video=this;
var $_controls=findControlsForVideo(_video);
var $_volume_bars=$_controls.find('.video_sound_volume_bar');
var $_sound_buttons=$_controls.find('.video_sound a');
/* Bind the volumechange event for the video */
$(_video).bind('volumechange', function() {
/* Set the height of the volume bars to match the new volume */
$_volume_bars.css("height", (_video.volume*100)+"%");
if (_video.muted) {
$_sound_buttons.removeClass('active');
} else {
$_sound_buttons.addClass('active');
}
});
/* Bind the click event for the sound buttons to mute/unmute */
$_sound_buttons.bind('click', function(e) {
e.preventDefault();
if (_video.muted) {
_video.muted=false;
} else {
_video.muted=true;
}
});
/* Set the initial values */
$_volume_bars.css("height", (_video.volume*100)+"%");
if (_video.muted) {
$_sound_buttons.removeClass('active');
} else {
$_sound_buttons.addClass('active');
}
});
/* For all video sound volumes */
$('.video_sound_volume').each(function() {
/* Store local references to the video to avoid having to repeatedly search */
var $_video=findVideoForElement(this);
/* Bind click functionality */
$(this).click(function(e) {
/* Calculate the decimal percentage (0-1.0) of the way up the bar the event happened at
then invert it as the bar is relative to the bottom, not the top. */
var _position=findEventPositionWithinElement(e);
var _decimal=1-(_position.top/$(this).height());
/* For all of the videos */
$_video.each(function(index, _video) {
/* Set the new volume */
_video.volume=_decimal;
});
});
});
}
Resources
The W3C spec for HTML5 video is available at:
http://www.w3.org/TR/html5/video.html
However, we would recommend the whatwg version as its linked table of contents makes it slightly more usable (even if the text is just as dense):
http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
Nicholas Davison Director of Web Development
Read more from the Engineering category. If you would like to leave a comment, click here: Comment or stay up to date with this post via RSS, or you can Trackback from your site.
Comments
Home Security Monitoring Mar 30, 2011 at 9:23pm
I've been absent for a while, but now I remember why I used to love this web site. Thank you, I will try and check back more often. How frequently you update your web site' Home Security Monitoring
phyprospada Jan 23, 2011 at 1:07pm
I love www.digitaria.com! Here I always find a lot of helpful information for myself. Thanks you for your work. Webmaster of http://loveepicentre.com and http://movieszone.eu Best regards
Post new comment