"use strict"; // Based on: // Sample Media Player using HTML5's Media API // // Ian Devlin (c) 2012 // http://iandevlin.com // http://twitter.com/iandevlin // // This was written as part of an article for the February 2013 edition of .net magazine (http://netmagazine.com/) // Wait for the DOM to be loaded before initialising the media player document.addEventListener("DOMContentLoaded", function() { initialiseMediaPlayer(); }, false); // Variables to store handles to various required elements var mediaPlayer; var playPauseBtn; var muteBtn; var progressBar; var mediaPlaybackMode = null; var mediaStartPlayTime; var mediaStartPauseTime; var mediaPlayedNotes; var recordedNotesArray = null; function initialiseMediaPlayer() { setPlaybackMode(); mediaStartPlayTime = null; mediaStartPauseTime = null; mediaPlayedNotes = {}; // Get a handle to the player mediaPlayer = document.getElementById('video'); // Get handles to each of the buttons and required elements playPauseBtn = document.getElementById('play-pause-button'); muteBtn = document.getElementById('mute-button'); progressBar = document.getElementById('progress-bar'); // Hide the browser's default controls mediaPlayer.controls = false; // Add a listener for the timeupdate event so we can update the progress bar mediaPlayer.addEventListener('timeupdate', updateProgressBar, false); // Add a listener so the video can be advanced if the progress bar is clicked on progressBar.addEventListener("change", progressBarChanged); // Pause the video when the slider handle is being dragged progressBar.addEventListener("mousedown", function() { mediaPlayer.pause(); }); // Play the video when the slider handle is dropped progressBar.addEventListener("mouseup", function() { mediaPlayer.play(); }); // Add a listener for the play and pause events so the buttons state can be updated mediaPlayer.addEventListener('play', function() { // Change the button to be a pause button changeButtonType(playPauseBtn, 'buttonx2 pause'); }, false); mediaPlayer.addEventListener('pause', function() { // Change the button to be a play button changeButtonType(playPauseBtn, 'buttonx2 play'); }, false); // need to work on this one more...how to know it's muted? mediaPlayer.addEventListener('volumechange', function(e) { // Update the button to be mute/unmute if (mediaPlayer.muted) changeButtonType(muteBtn, 'button unmute'); else changeButtonType(muteBtn, 'button mute'); }, false); mediaPlayer.addEventListener('ended', stopPlayer, false); } function togglePlayPause() { // If the mediaPlayer is currently paused or has ended console.log("togglePlayPause()"); //console.log("*** mediaPlayer (paused,ended): (" + mediaPlayer.paused + "," + mediaPlayer.ended + ")"); //console.log("*** currentTime = " + mediaPlayer.currentTime); if (mediaPlayer.paused || mediaPlayer.ended) { if (mediaStartPlayTime == null) { // Fresh play start console.log("**** mediaPlaybackMode = " + mediaPlaybackMode); mediaStartPlayTime = Date.now(); //console.log("*** mediaStartPlayTime=" + mediaStartPlayTime); mediaPlayedNotes[String(mediaStartPlayTime)] = []; } else { // Resume playing var mediaPauseBuildup = mediaStartPauseTime - Date.now(); // adjust the start play time to the pause is effectively ignored mediaStartPlayTime += mediaPauseBuildup; mediaStartPauseTime = null; } // Change the button to be a pause button changeButtonType(playPauseBtn, 'buttonx2 pause'); // Play the media mediaPlayer.play(); } // Otherwise it must currently be playing else { // put into pause state mediaStartPauseTime = Date.now(); // Change the button to be a play button changeButtonType(playPauseBtn, 'buttonx2 play'); // Pause the media mediaPlayer.pause(); console.log("*** mediaPlayedNotes = " + JSON.stringify(mediaPlayedNotes)); } } function _pad(n, width, z) { z = z || '0'; n = n + ''; return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n; } function convertSecsToTimeStr(time) { var int_mins = Math.floor(time / 60); var float_secs = time % 60; var padded_secs = _pad(float_secs.toFixed(1),4); // (2), 5 for 2 dec place return int_mins + ":" + padded_secs } function displayCurrentTime() { var currentTime = mediaPlayer.currentTime; var formattedTime = convertSecsToTimeStr(currentTime); $('#mediaPlayerCurrentTime').html(formattedTime); } function displayDuration(duration) { var formattedTime = convertSecsToTimeStr(duration); $('#mediaPlayerTotalTime').html(formattedTime); } // Stop the current media from playing, and return it to the start position function stopPlayer() { console.log("stopPlayer()"); mediaPlayer.pause(); if (mediaPlaybackMode == "record") { recordedNotesArray = mediaPlayedNotes[String(mediaStartPlayTime)]; if (recordedNotesArray.length>0) { // non-trival data recorded $('#save-recording-popup').dialog('open'); } } mediaStartPlayTime = null; mediaStartPauseTime = null; mediaPlayer.currentTime = 0; displayCurrentTime(); } // Changes the volume on the media player function changeVolume(direction) { if (direction === '+') mediaPlayer.volume += mediaPlayer.volume == 1 ? 0 : 0.1; else mediaPlayer.volume -= (mediaPlayer.volume == 0 ? 0 : 0.1); mediaPlayer.volume = parseFloat(mediaPlayer.volume).toFixed(1); } // Toggles the media player's mute and unmute status function toggleMute() { if (mediaPlayer.muted) { // Change the cutton to be a mute button changeButtonType(muteBtn, 'button mute'); // Unmute the media player mediaPlayer.muted = false; } else { // Change the button to be an unmute button changeButtonType(muteBtn, 'button unmute'); // Mute the media player mediaPlayer.muted = true; } } // Replays the media currently loaded in the player function replayMedia() { resetPlayer(); mediaPlayer.play(); } // Update the progress bar function updateProgressBar() { // Work out how much of the media has played via the duration and currentTime parameters var percentage = (100 / mediaPlayer.duration) * mediaPlayer.currentTime; // Update the progress bar's value progressBar.value = percentage; // Update the progress bar's text (for browsers that don't support the progress element) progressBar.innerHTML = Math.floor(percentage) + '% played'; displayCurrentTime(); } function progressBarChanged() { //console.log("**** progress bar changed!") // Calculate the new time var time = mediaPlayer.duration * (progressBar.value / 100); // Update the video time mediaPlayer.currentTime = time; displayCurrentTime(); } // Updates a button's title, innerHTML and CSS class to a certain value function changeButtonType(btn, value) { btn.title = value; btn.innerHTML = value; btn.className = value; } // Loads a video item into the media player function loadVideo() { for (var i = 0; i < arguments.length; i++) { var file = arguments[i].split('.'); var ext = file[file.length - 1]; // Check if this media can be played if (canPlayVideo(ext)) { // Reset the player, change the source file and load it resetPlayer(); mediaPlayer.src = arguments[i]; mediaPlayer.load(); break; } } } // Checks if the browser can play this particular type of file or not function canPlayVideo(ext) { var ableToPlay = mediaPlayer.canPlayType('video/' + ext); if (ableToPlay == '') return false; else return true; } // Resets the media player function resetPlayer() { mediaStartPlayTime = null; mediaStartPauseTime = null; // Reset the progress bar to 0 progressBar.value = 0; // Move the media back to the start mediaPlayer.currentTime = 0; displayCurrentTime(); // Ensure that the play pause button is set as 'play' changeButtonType(playPauseBtn, 'buttonx2 play'); } function setPlaybackMode() { //console.log("setPlaybackMode()"); mediaPlaybackMode = $('input[name=mpm-radio]:checked', '#mpmForm').val(); } function saveRecording() { var valid = true; var $save_name_input = $("#save-recording-name"); var save_name = $save_name_input.val(); if (save_name.match(/^\s*$/)) { valid = false; $save_name_input.addClass( "ui-state-error" ); } else { console.log("**** Saving under name '" + save_name +"': " + JSON.stringify(recordedNotesArray)); var $dialog = $('#save-recording-popup'); $dialog.dialog( "close" ); } return valid; } $(document).ready(function() { // Setup dialog var dialog = $('#save-recording-popup').dialog({ width : 500, height: 350, autoOpen: false, // Do not open on page load modal: true, // Freeze the background behind the overlay show: { effect: "blind", duration: 1000 }, hide: { effect: "blind", duration: 500 }, buttons: { "Save Recording": saveRecording, Cancel: function() { dialog.dialog("close"); } }, close: function() { form[0].reset(); $( "#save-recording-name" ).removeClass( "ui-state-error" ); } }); var form = dialog.find( "form" ).on( "submit", function( event ) { event.preventDefault(); }); });