From 97e40b52854a4177ac5da62ca567d4003867e08b Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 29 Mar 2012 16:06:36 +0200 Subject: [PATCH] Seeking works in firefox - Added support for indicating multiple buffered ranges (Firefox) - Added volume slider (Chromium) - Replaced stop button with faux pause button - Added 'ended' event handler --- mediagoblin/static/css/audio.css | 43 ++++++++-- mediagoblin/static/js/audio.js | 139 ++++++++++++++++++++++++------- 2 files changed, 148 insertions(+), 34 deletions(-) diff --git a/mediagoblin/static/css/audio.css b/mediagoblin/static/css/audio.css index 5f7a888a..387278ec 100644 --- a/mediagoblin/static/css/audio.css +++ b/mediagoblin/static/css/audio.css @@ -10,6 +10,7 @@ height: 100%; -webkit-transition: width .1s ease-out; -moz-transition: width .1s ease-out; + transition: width .1s ease-out; } .audio-control-play-pause { position: absolute; @@ -23,21 +24,37 @@ } .audio-control-play-pause.playing { color: #b71500; + letter-spacing: -17px; + margin-left: -7px; } .audio-control-play-pause.paused { + /* Warning: this means the the play button shows! */ color: rgb(134, 212, 177); } -.buffered { + +.buffered-indicators { position: absolute; bottom: 0; left: 0; height: 2px; - width: 0; - -webkit-transition: width 1s ease-out; - -moz-transition: width 1s ease-out; - background: rgba(134, 177, 212, 1); - cursor: pointer; } + .buffered-indicators div { + position: absolute; + height: 2px; + left: 0; + background: rgba(134, 177, 212, 1); + + -webkit-transition: left 1s ease-out; + -moz-transition: left 1s ease-out; + transition: left 1s ease-out; + + -webkit-transition: width 1s ease-out; + -moz-transition: width 1s ease-out; + transition: width 1s ease-out; + + cursor: pointer; + } + .seekbar { position: absolute; top: 0; @@ -45,9 +62,23 @@ width: 100%; height: 100%; } + .audio-currentTime { position: absolute; bottom: 0; right: 0; background: rgba(0, 0, 0, 0.7); } + +.audio-volume { + position: absolute; + left: 50px; + bottom: 10px; + opacity: 0.3; + -moz-transition: opacity .1s ease-in-out; + -webkit-transition: opacity .1s ease-in-out; + transition: opacity .1s ease-in-out; +} + .audio-spectrogram:hover .audio-volume { + opacity: 1; + } diff --git a/mediagoblin/static/js/audio.js b/mediagoblin/static/js/audio.js index 91d52f96..f50908a1 100644 --- a/mediagoblin/static/js/audio.js +++ b/mediagoblin/static/js/audio.js @@ -21,46 +21,110 @@ var audioPlayer = new Object(); (function (audioPlayer) { audioPlayer.init = function (audioElement) { audioPlayer.audioElement = audioElement; + console.log(audioElement); + attachEvents(); + $(audioElement).hide(); }; function attachEvents () { - audioPlayer.audioElement.addEventListener('durationchange', audioPlayer.durationChange, true); - audioPlayer.audioElement.addEventListener('timeupdate', audioPlayer.timeUpdate, true); - audioPlayer.audioElement.addEventListener('progress', audioPlayer.onProgress, true); + audioPlayer.audioElement.addEventListener( + 'durationchange', audioPlayer.durationChange, true); + audioPlayer.audioElement.addEventListener( + 'timeupdate', audioPlayer.timeUpdate, true); + audioPlayer.audioElement.addEventListener( + 'progress', audioPlayer.onProgress, true); + audioPlayer.audioElement.addEventListener( + 'ended', audioPlayer.onEnded, true); + $(document).ready( function () { - $('.audio-spectrogram').delegate('.seekbar', 'click', audioPlayer.onSeek); - $('.audio-spectrogram').delegate('.audio-control-play-pause', 'click', audioPlayer.playPause); + $('.audio-spectrogram').delegate( + '.seekbar', 'click', audioPlayer.onSeek); + $('.audio-spectrogram').delegate( + '.audio-control-play-pause', 'click', audioPlayer.playPause); + $('.audio-spectrogram').delegate( + '.audio-volume', 'change', audioPlayer.onVolumeChange); + $('.audio-media').delegate( + '.audio-spectrogram', 'attachedControls', + audioPlayer.onControlsAttached); }); } - audioPlayer.onProgress = function(a, b, c) { - console.log(a, b, c); - buffered = audioPlayer.audioElement.buffered; + audioPlayer.onVolumeChange = function(e) { + console.log('volume change', e); + audioPlayer.audioElement.volume = e.target.value; + } + + audioPlayer.onControlsAttached = function(e) { + console.log('Controls attached', e); + $('.audio-spectrogram .audio-volume').val( + Math.round(audioPlayer.audioElement.volume, 2)); + } + + audioPlayer.onProgress = function(e) { + /** + * Handler for file download progress + */ + console.log(e); + + var buffered = audioPlayer.audioElement.buffered; ranges = new Array(); - for (i = 0; i < buffered.length; i++) { - ranges[i] = new Array(); - ranges[i][0] = buffered.start(i); - ranges[i][1] = buffered.end(i); + var indicators = $('.audio-spectrogram .buffered-indicators div'); + + for (var i = 0; i < buffered.length; i++) { + if (!(i in indicators)) { + $('
') + .appendTo($('.audio-spectrogram .buffered-indicators')) + .fadeIn(500); + indicators = $('.audio-spectrogram .buffered-indicators div'); + } + var posStart = ((buffered.start(i) / audioPlayer.audioElement.duration) + * audioPlayer.imageElement.width()); + var posStop = ((buffered.end(i) / audioPlayer.audioElement.duration) + * audioPlayer.imageElement.width()); + console.log('indicators', indicators); + + var indicator = $(indicators[i]); + + indicator.css('left', posStart); + indicator.css('width', posStop - posStart); + } + + /* + * Clean up unused indicators + */ + if (indicators.length > buffered.length) { + for (var i = buffered.length; i < indicators.length; i++) { + $(indicators[i]).fadeOut(500, function () { + this.remove(); + }); + } } - console.log('ranges', ranges); - $('.audio-spectrogram .buffered').width( - (ranges[0][1] / audioPlayer.audioElement.duration) * audioPlayer.imageElement.width()); }; audioPlayer.onSeek = function (e) { + /** + * Callback handler for seek event, which is a .click() event on the + * .seekbar element + */ console.log('onSeek', e); - im = audioPlayer.imageElement; - pos = e.offsetX / im.width(); + + var im = audioPlayer.imageElement; + var pos = (e.offsetX || e.originalEvent.layerX) / im.width(); + audioPlayer.audioElement.currentTime = pos * audioPlayer.audioElement.duration; audioPlayer.audioElement.play(); audioPlayer.setState(audioPlayer.PLAYING); }; + audioPlayer.onEnded = function (e) { + audioPlayer.setState(audioPlayer.PAUSED); + } + audioPlayer.playPause = function (e) { console.log('playPause', e); if (audioPlayer.audioElement.paused) { @@ -81,13 +145,15 @@ var audioPlayer = new Object(); audioPlayer.setState = function (state) { if (state == audioPlayer.state) { return; + } else { + audioPlayer.state = state; } switch (state) { case audioPlayer.PLAYING: $('.audio-spectrogram .audio-control-play-pause') .removeClass('paused').addClass('playing') - .text('■'); + .text('▮▮'); break; case audioPlayer.PAUSED: $('.audio-spectrogram .audio-control-play-pause') @@ -98,37 +164,55 @@ var audioPlayer = new Object(); }; audioPlayer.durationChange = function () { - duration = audioPlayer.audioElement.duration; + // ??? }; audioPlayer.timeUpdate = function () { - currentTime = audioPlayer.audioElement.currentTime; - playhead = audioPlayer.imageElement.parent().find('.playhead'); - playhead.css('width', (currentTime / audioPlayer.audioElement.duration) * audioPlayer.imageElement.width()); - time = formatTime(currentTime); - duration = formatTime(audioPlayer.audioElement.duration); - audioPlayer.imageElement.parent().find('.audio-currentTime').text(time + '/' + duration); + /** + * Callback handler for the timeupdate event, responsible for + * updating the playhead + */ + var currentTime = audioPlayer.audioElement.currentTime; + var playhead = audioPlayer.imageElement.parent().find('.playhead'); + playhead.css('width', (currentTime / audioPlayer.audioElement.duration) + * audioPlayer.imageElement.width()); + var time = formatTime(currentTime); + var duration = formatTime(audioPlayer.audioElement.duration); + audioPlayer.imageElement.parent() + .find('.audio-currentTime') + .text(time + '/' + duration); }; function formatTime(seconds) { + /** + * Format a time duration in (hh:)?mm:ss manner + */ var h = Math.floor(seconds / (60 * 60)); var m = Math.floor((seconds - h * 60 * 60) / 60); var s = Math.round(seconds - h * 60 * 60 - m * 60); return '' + (h ? (h < 10 ? '0' + h : h) + ':' : '') + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s); } + audioPlayer.formatTime = formatTime; + audioPlayer.attachToImage = function (imageElement) { /** * Attach the player to an image element */ console.log(imageElement); - im = $(imageElement); + + var im = $(imageElement); + audioPlayer.imageElement = im; + $('
').appendTo(im.parent()); - $('
').appendTo(im.parent()); + $('
').appendTo(im.parent()); $('
').appendTo(im.parent()); $('
▶
').appendTo(im.parent()); $('
00:00
').appendTo(im.parent()); + $('').appendTo(im.parent()); + $('.audio-spectrogram').trigger('attachedControls'); }; })(audioPlayer); @@ -143,4 +227,3 @@ $(document).ready(function () { audioPlayer.init(audioElements[0]); audioPlayer.attachToImage($('.audio-spectrogram img')[0]); }); - -- 2.25.1