[29877] | 1 | "use strict";
|
---|
| 2 |
|
---|
| 3 | // Based on:
|
---|
| 4 | // Sample Media Player using HTML5's Media API
|
---|
[29863] | 5 | //
|
---|
| 6 | // Ian Devlin (c) 2012
|
---|
| 7 | // http://iandevlin.com
|
---|
| 8 | // http://twitter.com/iandevlin
|
---|
| 9 | //
|
---|
| 10 | // This was written as part of an article for the February 2013 edition of .net magazine (http://netmagazine.com/)
|
---|
| 11 |
|
---|
| 12 | // Wait for the DOM to be loaded before initialising the media player
|
---|
| 13 | document.addEventListener("DOMContentLoaded", function() { initialiseMediaPlayer(); }, false);
|
---|
| 14 |
|
---|
| 15 | // Variables to store handles to various required elements
|
---|
| 16 | var mediaPlayer;
|
---|
| 17 | var playPauseBtn;
|
---|
| 18 | var muteBtn;
|
---|
| 19 | var progressBar;
|
---|
| 20 |
|
---|
[29877] | 21 | var mediaPlaybackMode = null;
|
---|
| 22 |
|
---|
[29863] | 23 | var mediaStartPlayTime;
|
---|
| 24 | var mediaStartPauseTime;
|
---|
| 25 | var mediaPlayedNotes;
|
---|
| 26 |
|
---|
[29877] | 27 | var recordedNotesArray = null;
|
---|
| 28 |
|
---|
[29863] | 29 | function initialiseMediaPlayer() {
|
---|
| 30 |
|
---|
[29877] | 31 | setPlaybackMode();
|
---|
| 32 |
|
---|
[29863] | 33 | mediaStartPlayTime = null;
|
---|
| 34 | mediaStartPauseTime = null;
|
---|
| 35 | mediaPlayedNotes = {};
|
---|
| 36 |
|
---|
| 37 | // Get a handle to the player
|
---|
| 38 | mediaPlayer = document.getElementById('video');
|
---|
| 39 |
|
---|
| 40 | // Get handles to each of the buttons and required elements
|
---|
| 41 | playPauseBtn = document.getElementById('play-pause-button');
|
---|
| 42 | muteBtn = document.getElementById('mute-button');
|
---|
| 43 | progressBar = document.getElementById('progress-bar');
|
---|
| 44 |
|
---|
| 45 | // Hide the browser's default controls
|
---|
| 46 | mediaPlayer.controls = false;
|
---|
| 47 |
|
---|
| 48 | // Add a listener for the timeupdate event so we can update the progress bar
|
---|
| 49 | mediaPlayer.addEventListener('timeupdate', updateProgressBar, false);
|
---|
| 50 |
|
---|
| 51 | // Add a listener so the video can be advanced if the progress bar is clicked on
|
---|
| 52 | progressBar.addEventListener("change", progressBarChanged);
|
---|
| 53 |
|
---|
| 54 |
|
---|
| 55 | // Pause the video when the slider handle is being dragged
|
---|
| 56 | progressBar.addEventListener("mousedown", function() {
|
---|
| 57 | mediaPlayer.pause();
|
---|
| 58 | });
|
---|
| 59 |
|
---|
| 60 | // Play the video when the slider handle is dropped
|
---|
| 61 | progressBar.addEventListener("mouseup", function() {
|
---|
| 62 | mediaPlayer.play();
|
---|
| 63 | });
|
---|
| 64 |
|
---|
[29877] | 65 | // Add a listener for the play and pause events so the buttons state can be updated
|
---|
| 66 | mediaPlayer.addEventListener('play', function() {
|
---|
| 67 | // Change the button to be a pause button
|
---|
| 68 | changeButtonType(playPauseBtn, 'buttonx2 pause');
|
---|
| 69 | }, false);
|
---|
| 70 | mediaPlayer.addEventListener('pause', function() {
|
---|
| 71 | // Change the button to be a play button
|
---|
| 72 | changeButtonType(playPauseBtn, 'buttonx2 play');
|
---|
| 73 | }, false);
|
---|
[29863] | 74 |
|
---|
[29877] | 75 | // need to work on this one more...how to know it's muted?
|
---|
| 76 | mediaPlayer.addEventListener('volumechange', function(e) {
|
---|
| 77 | // Update the button to be mute/unmute
|
---|
| 78 | if (mediaPlayer.muted) changeButtonType(muteBtn, 'button unmute');
|
---|
| 79 | else changeButtonType(muteBtn, 'button mute');
|
---|
| 80 | }, false);
|
---|
| 81 |
|
---|
| 82 | mediaPlayer.addEventListener('ended', stopPlayer, false);
|
---|
[29863] | 83 | }
|
---|
| 84 |
|
---|
| 85 | function togglePlayPause() {
|
---|
[29877] | 86 | // If the mediaPlayer is currently paused or has ended
|
---|
| 87 | console.log("togglePlayPause()");
|
---|
| 88 | //console.log("*** mediaPlayer (paused,ended): (" + mediaPlayer.paused + "," + mediaPlayer.ended + ")");
|
---|
| 89 | //console.log("*** currentTime = " + mediaPlayer.currentTime);
|
---|
| 90 |
|
---|
[29863] | 91 | if (mediaPlayer.paused || mediaPlayer.ended) {
|
---|
| 92 | if (mediaStartPlayTime == null) {
|
---|
[29877] | 93 | // Fresh play start
|
---|
| 94 | console.log("**** mediaPlaybackMode = " + mediaPlaybackMode);
|
---|
| 95 |
|
---|
[29863] | 96 | mediaStartPlayTime = Date.now();
|
---|
| 97 | //console.log("*** mediaStartPlayTime=" + mediaStartPlayTime);
|
---|
| 98 | mediaPlayedNotes[String(mediaStartPlayTime)] = [];
|
---|
| 99 |
|
---|
| 100 | }
|
---|
| 101 | else {
|
---|
[29877] | 102 | // Resume playing
|
---|
[29863] | 103 | var mediaPauseBuildup = mediaStartPauseTime - Date.now();
|
---|
| 104 |
|
---|
| 105 | // adjust the start play time to the pause is effectively ignored
|
---|
| 106 | mediaStartPlayTime += mediaPauseBuildup;
|
---|
| 107 | mediaStartPauseTime = null;
|
---|
| 108 |
|
---|
| 109 | }
|
---|
| 110 |
|
---|
| 111 | // Change the button to be a pause button
|
---|
[29867] | 112 | changeButtonType(playPauseBtn, 'buttonx2 pause');
|
---|
[29863] | 113 | // Play the media
|
---|
| 114 | mediaPlayer.play();
|
---|
| 115 | }
|
---|
| 116 | // Otherwise it must currently be playing
|
---|
| 117 | else {
|
---|
[29877] | 118 | // put into pause state
|
---|
[29863] | 119 |
|
---|
[29877] | 120 | mediaStartPauseTime = Date.now();
|
---|
| 121 |
|
---|
[29863] | 122 | // Change the button to be a play button
|
---|
[29867] | 123 | changeButtonType(playPauseBtn, 'buttonx2 play');
|
---|
[29863] | 124 | // Pause the media
|
---|
| 125 | mediaPlayer.pause();
|
---|
| 126 |
|
---|
| 127 | console.log("*** mediaPlayedNotes = " + JSON.stringify(mediaPlayedNotes));
|
---|
| 128 | }
|
---|
| 129 | }
|
---|
| 130 |
|
---|
[29877] | 131 | function _pad(n, width, z) {
|
---|
[29867] | 132 | z = z || '0';
|
---|
| 133 | n = n + '';
|
---|
| 134 | return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
|
---|
| 135 | }
|
---|
| 136 |
|
---|
| 137 | function convertSecsToTimeStr(time)
|
---|
| 138 | {
|
---|
| 139 | var int_mins = Math.floor(time / 60);
|
---|
| 140 | var float_secs = time % 60;
|
---|
| 141 |
|
---|
[29877] | 142 | var padded_secs = _pad(float_secs.toFixed(1),4); // (2), 5 for 2 dec place
|
---|
[29867] | 143 | return int_mins + ":" + padded_secs
|
---|
| 144 | }
|
---|
| 145 |
|
---|
| 146 |
|
---|
| 147 | function displayCurrentTime()
|
---|
| 148 | {
|
---|
| 149 | var currentTime = mediaPlayer.currentTime;
|
---|
| 150 | var formattedTime = convertSecsToTimeStr(currentTime);
|
---|
| 151 | $('#mediaPlayerCurrentTime').html(formattedTime);
|
---|
| 152 | }
|
---|
| 153 |
|
---|
| 154 | function displayDuration(duration)
|
---|
| 155 | {
|
---|
| 156 | var formattedTime = convertSecsToTimeStr(duration);
|
---|
| 157 | $('#mediaPlayerTotalTime').html(formattedTime);
|
---|
| 158 | }
|
---|
| 159 |
|
---|
| 160 |
|
---|
[29863] | 161 | // Stop the current media from playing, and return it to the start position
|
---|
[29877] | 162 |
|
---|
[29867] | 163 | function stopPlayer()
|
---|
| 164 | {
|
---|
[29877] | 165 | console.log("stopPlayer()");
|
---|
[29867] | 166 | mediaPlayer.pause();
|
---|
[29877] | 167 |
|
---|
| 168 | if (mediaPlaybackMode == "record") {
|
---|
| 169 | recordedNotesArray = mediaPlayedNotes[String(mediaStartPlayTime)];
|
---|
| 170 | if (recordedNotesArray.length>0) {
|
---|
| 171 | // non-trival data recorded
|
---|
| 172 | $('#save-recording-popup').dialog('open');
|
---|
| 173 | }
|
---|
| 174 | }
|
---|
| 175 |
|
---|
| 176 | mediaStartPlayTime = null;
|
---|
| 177 | mediaStartPauseTime = null;
|
---|
| 178 |
|
---|
[29867] | 179 | mediaPlayer.currentTime = 0;
|
---|
| 180 | displayCurrentTime();
|
---|
[29877] | 181 |
|
---|
[29863] | 182 | }
|
---|
| 183 |
|
---|
| 184 | // Changes the volume on the media player
|
---|
| 185 | function changeVolume(direction) {
|
---|
| 186 | if (direction === '+') mediaPlayer.volume += mediaPlayer.volume == 1 ? 0 : 0.1;
|
---|
| 187 | else mediaPlayer.volume -= (mediaPlayer.volume == 0 ? 0 : 0.1);
|
---|
| 188 | mediaPlayer.volume = parseFloat(mediaPlayer.volume).toFixed(1);
|
---|
| 189 | }
|
---|
| 190 |
|
---|
| 191 | // Toggles the media player's mute and unmute status
|
---|
| 192 | function toggleMute() {
|
---|
| 193 | if (mediaPlayer.muted) {
|
---|
| 194 | // Change the cutton to be a mute button
|
---|
[29867] | 195 | changeButtonType(muteBtn, 'button mute');
|
---|
[29863] | 196 | // Unmute the media player
|
---|
| 197 | mediaPlayer.muted = false;
|
---|
| 198 | }
|
---|
| 199 | else {
|
---|
| 200 | // Change the button to be an unmute button
|
---|
[29867] | 201 | changeButtonType(muteBtn, 'button unmute');
|
---|
[29863] | 202 | // Mute the media player
|
---|
| 203 | mediaPlayer.muted = true;
|
---|
| 204 | }
|
---|
| 205 | }
|
---|
| 206 |
|
---|
| 207 | // Replays the media currently loaded in the player
|
---|
| 208 | function replayMedia() {
|
---|
| 209 | resetPlayer();
|
---|
| 210 | mediaPlayer.play();
|
---|
| 211 | }
|
---|
| 212 |
|
---|
[29877] | 213 |
|
---|
| 214 |
|
---|
| 215 |
|
---|
[29863] | 216 | // Update the progress bar
|
---|
| 217 | function updateProgressBar() {
|
---|
[29867] | 218 | // Work out how much of the media has played via the duration and currentTime parameters
|
---|
| 219 | var percentage = (100 / mediaPlayer.duration) * mediaPlayer.currentTime;
|
---|
| 220 |
|
---|
| 221 | // Update the progress bar's value
|
---|
| 222 | progressBar.value = percentage;
|
---|
| 223 |
|
---|
| 224 | // Update the progress bar's text (for browsers that don't support the progress element)
|
---|
| 225 | progressBar.innerHTML = Math.floor(percentage) + '% played';
|
---|
| 226 |
|
---|
| 227 | displayCurrentTime();
|
---|
[29863] | 228 | }
|
---|
| 229 |
|
---|
| 230 | function progressBarChanged() {
|
---|
| 231 | //console.log("**** progress bar changed!")
|
---|
| 232 | // Calculate the new time
|
---|
| 233 | var time = mediaPlayer.duration * (progressBar.value / 100);
|
---|
| 234 |
|
---|
| 235 | // Update the video time
|
---|
| 236 | mediaPlayer.currentTime = time;
|
---|
[29867] | 237 | displayCurrentTime();
|
---|
[29863] | 238 | }
|
---|
| 239 |
|
---|
| 240 | // Updates a button's title, innerHTML and CSS class to a certain value
|
---|
| 241 | function changeButtonType(btn, value) {
|
---|
| 242 | btn.title = value;
|
---|
| 243 | btn.innerHTML = value;
|
---|
| 244 | btn.className = value;
|
---|
| 245 | }
|
---|
| 246 |
|
---|
| 247 | // Loads a video item into the media player
|
---|
| 248 | function loadVideo() {
|
---|
| 249 | for (var i = 0; i < arguments.length; i++) {
|
---|
| 250 | var file = arguments[i].split('.');
|
---|
| 251 | var ext = file[file.length - 1];
|
---|
| 252 | // Check if this media can be played
|
---|
| 253 | if (canPlayVideo(ext)) {
|
---|
| 254 | // Reset the player, change the source file and load it
|
---|
| 255 | resetPlayer();
|
---|
| 256 | mediaPlayer.src = arguments[i];
|
---|
| 257 | mediaPlayer.load();
|
---|
| 258 | break;
|
---|
| 259 | }
|
---|
| 260 | }
|
---|
| 261 | }
|
---|
| 262 |
|
---|
| 263 | // Checks if the browser can play this particular type of file or not
|
---|
| 264 | function canPlayVideo(ext) {
|
---|
| 265 | var ableToPlay = mediaPlayer.canPlayType('video/' + ext);
|
---|
| 266 | if (ableToPlay == '') return false;
|
---|
| 267 | else return true;
|
---|
| 268 | }
|
---|
| 269 |
|
---|
[29877] | 270 |
|
---|
[29863] | 271 | // Resets the media player
|
---|
| 272 | function resetPlayer() {
|
---|
[29867] | 273 | mediaStartPlayTime = null;
|
---|
| 274 | mediaStartPauseTime = null;
|
---|
| 275 |
|
---|
| 276 | // Reset the progress bar to 0
|
---|
| 277 | progressBar.value = 0;
|
---|
| 278 | // Move the media back to the start
|
---|
| 279 | mediaPlayer.currentTime = 0;
|
---|
| 280 | displayCurrentTime();
|
---|
| 281 | // Ensure that the play pause button is set as 'play'
|
---|
[29877] | 282 | changeButtonType(playPauseBtn, 'buttonx2 play');
|
---|
| 283 | }
|
---|
| 284 |
|
---|
| 285 |
|
---|
| 286 | function setPlaybackMode()
|
---|
| 287 | {
|
---|
| 288 | //console.log("setPlaybackMode()");
|
---|
| 289 | mediaPlaybackMode = $('input[name=mpm-radio]:checked', '#mpmForm').val();
|
---|
| 290 | }
|
---|
| 291 |
|
---|
| 292 |
|
---|
| 293 |
|
---|
| 294 | function saveRecording()
|
---|
| 295 | {
|
---|
| 296 | var valid = true;
|
---|
| 297 |
|
---|
| 298 | var $save_name_input = $("#save-recording-name");
|
---|
| 299 | var save_name = $save_name_input.val();
|
---|
| 300 |
|
---|
| 301 | if (save_name.match(/^\s*$/)) {
|
---|
| 302 | valid = false;
|
---|
| 303 | $save_name_input.addClass( "ui-state-error" );
|
---|
| 304 | }
|
---|
| 305 | else {
|
---|
| 306 | console.log("**** Saving under name '" + save_name +"': " + JSON.stringify(recordedNotesArray));
|
---|
| 307 |
|
---|
| 308 | var $dialog = $('#save-recording-popup');
|
---|
| 309 |
|
---|
| 310 | $dialog.dialog( "close" );
|
---|
| 311 | }
|
---|
| 312 |
|
---|
| 313 | return valid;
|
---|
| 314 | }
|
---|
| 315 |
|
---|
| 316 |
|
---|
| 317 | $(document).ready(function() {
|
---|
| 318 | // Setup dialog
|
---|
| 319 |
|
---|
| 320 | var dialog = $('#save-recording-popup').dialog({
|
---|
| 321 | width : 500,
|
---|
| 322 | height: 350,
|
---|
| 323 | autoOpen: false, // Do not open on page load
|
---|
| 324 | modal: true, // Freeze the background behind the overlay
|
---|
| 325 |
|
---|
| 326 | show: {
|
---|
| 327 | effect: "blind",
|
---|
| 328 | duration: 1000
|
---|
| 329 | },
|
---|
| 330 | hide: {
|
---|
| 331 | effect: "blind",
|
---|
| 332 | duration: 500
|
---|
| 333 | },
|
---|
| 334 |
|
---|
| 335 | buttons: {
|
---|
| 336 | "Save Recording": saveRecording,
|
---|
| 337 | Cancel: function() {
|
---|
| 338 | dialog.dialog("close");
|
---|
| 339 | }
|
---|
| 340 | },
|
---|
| 341 | close: function() {
|
---|
| 342 | form[0].reset();
|
---|
| 343 | $( "#save-recording-name" ).removeClass( "ui-state-error" );
|
---|
| 344 | }
|
---|
| 345 | });
|
---|
| 346 |
|
---|
| 347 | var form = dialog.find( "form" ).on( "submit", function( event ) {
|
---|
| 348 | event.preventDefault();
|
---|
| 349 | });
|
---|
| 350 |
|
---|
| 351 |
|
---|
| 352 | });
|
---|
| 353 |
|
---|