source: main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/media-player.js@ 30093

Last change on this file since 30093 was 30093, checked in by davidb, 9 years ago

Development work done in at JCDL

File size: 17.9 KB
Line 
1//"use strict";
2
3// Based on:
4// Sample Media Player using HTML5's Media API
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
13document.addEventListener("DOMContentLoaded", function() { initialiseMediaPlayer(); }, false);
14
15// Variables to store handles to various required elements
16var mediaPlayer;
17var playPauseBtn;
18var muteBtn;
19var progressBar;
20
21var mediaPlaybackMode = null;
22
23var mediaStartPlayTime;
24var mediaStartPauseTime;
25var mediaPlayedNotes;
26
27var recordedNotesArray = null;
28
29var hasLocalStorage = (typeof(Storage) !== "undefined");
30var trackEditor = null;
31
32function initialiseMediaPlayer() {
33
34 setPlaybackMode();
35
36 mediaStartPlayTime = null;
37 mediaStartPauseTime = null;
38 mediaPlayedNotes = {};
39
40 // Get a handle to the player
41 mediaPlayer = document.getElementById('video');
42
43 // Get handles to each of the buttons and required elements
44 playPauseBtn = document.getElementById('play-pause-button');
45 muteBtn = document.getElementById('mute-button');
46 progressBar = document.getElementById('progress-bar');
47
48 // Hide the browser's default controls
49 mediaPlayer.controls = false;
50
51 // Make the default volume a little bit quiter, so instruments can be heard over it
52 mediaPlayer.volume = 0.3
53
54 // Add a listener for the timeupdate event so we can update the progress bar
55 mediaPlayer.addEventListener('timeupdate', updateProgressBar, false);
56
57 // Add a listener so the video can be advanced if the progress bar is clicked on
58 progressBar.addEventListener("change", progressBarChanged);
59
60
61 // Pause the video when the slider handle is being dragged
62 progressBar.addEventListener("mousedown", function() {
63 mediaPlayer.pause();
64 });
65
66 // Play the video when the slider handle is dropped
67 progressBar.addEventListener("mouseup", function() {
68 mediaPlayer.play();
69 });
70
71 // Add a listener for the play and pause events so the buttons state can be updated
72 mediaPlayer.addEventListener('play', function() {
73 // Change the button to be a pause button
74 changeButtonType(playPauseBtn, 'buttonx2 pause');
75 }, false);
76 mediaPlayer.addEventListener('pause', function() {
77 // Change the button to be a play button
78 changeButtonType(playPauseBtn, 'buttonx2 play');
79 }, false);
80
81 // need to work on this one more...how to know it's muted?
82 mediaPlayer.addEventListener('volumechange', function(e) {
83 // Update the button to be mute/unmute
84 if (mediaPlayer.muted) changeButtonType(muteBtn, 'button unmute');
85 else changeButtonType(muteBtn, 'button mute');
86 }, false);
87
88 mediaPlayer.addEventListener('ended', stopPlayer, false);
89}
90
91function togglePlayPause() {
92 //e = e || window.event;
93 // If the mediaPlayer is currently paused or has ended
94 console.log("togglePlayPause()");
95
96 //console.log("**** event e = " + e);
97
98 //console.log("*** mediaPlayer (paused,ended): (" + mediaPlayer.paused + "," + mediaPlayer.ended + ")");
99 //console.log("*** currentTime = " + mediaPlayer.currentTime);
100
101 if (mediaPlayer.paused || mediaPlayer.ended) {
102 if (mediaStartPlayTime == null) {
103 // Fresh play start
104 console.log("**** mediaPlaybackMode = " + mediaPlaybackMode);
105
106 mediaStartPlayTime = Date.now();
107 //console.log("*** mediaStartPlayTime=" + mediaStartPlayTime);
108 mediaPlayedNotes[String(mediaStartPlayTime)] = [];
109
110 }
111 else {
112 // Resume playing
113 var mediaPauseBuildup = mediaStartPauseTime - Date.now();
114
115 // adjust the start play time to the pause is effectively ignored
116 mediaStartPlayTime += mediaPauseBuildup;
117 mediaStartPauseTime = null;
118
119 }
120
121 // Change the button to be a pause button
122 changeButtonType(playPauseBtn, 'buttonx2 pause');
123 // Play the media
124 mediaPlayer.play();
125 }
126 // Otherwise it must currently be playing
127 else {
128 // put into pause state
129
130 mediaStartPauseTime = Date.now();
131
132 // Change the button to be a play button
133 changeButtonType(playPauseBtn, 'buttonx2 play');
134 // Pause the media
135 mediaPlayer.pause();
136
137 console.log("*** mediaPlayedNotes = " + JSON.stringify(mediaPlayedNotes));
138 }
139
140 // Loose keyboard focus so space-bar for global pause doesn't cause a focused play-button event
141 $('#play-pause-button').blur();
142
143
144}
145
146function _pad(n, width, z) {
147 z = z || '0';
148 n = n + '';
149 return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
150}
151
152function convertSecsToTimeStr(time)
153{
154 var int_mins = Math.floor(time / 60);
155 var float_secs = time % 60;
156
157 var padded_secs = _pad(float_secs.toFixed(1),4); // (2), 5 for 2 dec place
158 return int_mins + ":" + padded_secs
159}
160
161
162function displayCurrentTime()
163{
164 var currentTime = mediaPlayer.currentTime;
165 var formattedTime = convertSecsToTimeStr(currentTime);
166 $('#mediaPlayerCurrentTime').html(formattedTime);
167
168 updateGameOnCurrentTimeline();
169}
170
171function displayDuration(duration)
172{
173 var formattedTime = convertSecsToTimeStr(duration);
174 $('#mediaPlayerTotalTime').html(formattedTime);
175}
176
177
178// Stop the current media from playing, and return it to the start position
179
180function stopPlayer()
181{
182 console.log("stopPlayer()");
183 mediaPlayer.pause();
184
185 if (mediaPlaybackMode == "record") {
186 recordedNotesArray = mediaPlayedNotes[String(mediaStartPlayTime)];
187 if (recordedNotesArray.length>0) {
188 // non-trival data recorded
189 $('#save-recording-popup').dialog('open');
190 }
191 }
192
193 mediaStartPlayTime = null;
194 mediaStartPauseTime = null;
195
196 mediaPlayer.currentTime = 0;
197 displayCurrentTime();
198
199}
200
201// Changes the volume on the media player
202function changeVolume(direction) {
203 if (direction === '+') mediaPlayer.volume += mediaPlayer.volume == 1 ? 0 : 0.1;
204 else mediaPlayer.volume -= (mediaPlayer.volume == 0 ? 0 : 0.1);
205 mediaPlayer.volume = parseFloat(mediaPlayer.volume).toFixed(1);
206}
207
208// Toggles the media player's mute and unmute status
209function toggleMute() {
210 if (mediaPlayer.muted) {
211 // Change the cutton to be a mute button
212 changeButtonType(muteBtn, 'button mute');
213 // Unmute the media player
214 mediaPlayer.muted = false;
215 }
216 else {
217 // Change the button to be an unmute button
218 changeButtonType(muteBtn, 'button unmute');
219 // Mute the media player
220 mediaPlayer.muted = true;
221 }
222}
223
224// Replays the media currently loaded in the player
225function replayMedia() {
226 resetPlayer();
227 mediaPlayer.play();
228}
229
230
231
232
233// Update the progress bar
234function updateProgressBar() {
235 // Work out how much of the media has played via the duration and currentTime parameters
236 var percentage = (100 / mediaPlayer.duration) * mediaPlayer.currentTime;
237
238 // Update the progress bar's value
239 progressBar.value = percentage;
240
241 // Update the progress bar's text (for browsers that don't support the progress element)
242 progressBar.innerHTML = Math.floor(percentage) + '% played';
243
244 displayCurrentTime();
245}
246
247function progressBarChanged() {
248 //console.log("**** progress bar changed!")
249 // Calculate the new time
250 var time = mediaPlayer.duration * (progressBar.value / 100);
251
252 // Update the video time
253 mediaPlayer.currentTime = time;
254 displayCurrentTime();
255}
256
257// Updates a button's title, innerHTML and CSS class to a certain value
258function changeButtonType(btn, value) {
259 //btn.title = value;
260 btn.innerHTML = value;
261 btn.className = value;
262}
263
264// Loads a video item into the media player
265function loadVideo() {
266 for (var i = 0; i < arguments.length; i++) {
267 var file = arguments[i].split('.');
268 var ext = file[file.length - 1];
269 // Check if this media can be played
270 if (canPlayVideo(ext)) {
271 // Reset the player, change the source file and load it
272 resetPlayer();
273 mediaPlayer.src = arguments[i];
274 mediaPlayer.load();
275 break;
276 }
277 }
278}
279
280// Checks if the browser can play this particular type of file or not
281function canPlayVideo(ext) {
282 var ableToPlay = mediaPlayer.canPlayType('video/' + ext);
283 if (ableToPlay == '') return false;
284 else return true;
285}
286
287
288// Resets the media player
289function resetPlayer() {
290 mediaStartPlayTime = null;
291 mediaStartPauseTime = null;
292
293 // Reset the progress bar to 0
294 progressBar.value = 0;
295 // Move the media back to the start
296 mediaPlayer.currentTime = 0;
297 displayCurrentTime();
298 // Ensure that the play pause button is set as 'play'
299 changeButtonType(playPauseBtn, 'buttonx2 play');
300}
301
302
303function setPlaybackMode()
304{
305 //console.log("setPlaybackMode()");
306 mediaPlaybackMode = $('input[name=mpm-radio]:checked', '#mpmForm').val();
307}
308
309
310function toggleGraphicEQ()
311{
312 $('#grapheqControlL').toggle();
313 $('#grapheqControlR').toggle();
314
315 return false;
316
317}
318
319function saveRecording()
320{
321 var valid = true;
322
323 var $save_name_input = $("#save-recording-name");
324 var save_name = $save_name_input.val();
325
326 if (save_name.match(/^\s*$/)) {
327 valid = false;
328 $save_name_input.addClass( "ui-state-error" );
329 }
330 else {
331
332 if (hasLocalStorage) {
333 var docOID = gs.cgiParams.d;
334
335
336 // Force reset of what has been stored for this item
337 //localStorage.setItem(docOID, JSON.stringify(null));
338
339 var docStorage = getDocStorage(docOID);
340
341 //var docStorageStr = localStorage.getItem(docOID);
342 //console.log("*** retrived docStorageStr: " + JSON.stringify(docStorage));
343
344 //// var docStorage = (docStorageStr != null) ? eval("("+docStorageStr+")") : {palTracks:{}, popTracks:{}};
345 //var docStorage = eval("("+docStorageStr+")") || {palTracks:{}, popTracks:{}};
346 //console.log("*** set up docStorage: " + JSON.stringify(docStorage));
347
348 var palTracks = getPalTracks(docOID);
349
350 // Make timing information relative to ba base value
351 var num_rec_notes = recordedNotesArray.length;
352
353 var base_time_sct = recordedNotesArray[0].startCurrentTime;
354 var base_time_mnon = recordedNotesArray[0].midiNoteOn;
355 var base_time_moff = recordedNotesArray[0].midiNoteOff;
356 var base_time_spt = recordedNotesArray[0].startPercTime;
357
358 for (var i=0; i<num_rec_notes; i++) {
359 recordedNotesArray[i].startCurrentTime -= base_time_sct;
360 recordedNotesArray[i].midiNoteOn -= base_time_mnon;
361 recordedNotesArray[i].midiNoteOff -= base_time_moff;
362 recordedNotesArray[i].startPercTime -= base_time_spt;
363 }
364
365 palTracks[save_name] = [ { name: save_name + " 1", baseCTime: base_time_sct, events: recordedNotesArray } ]
366
367 //console.log("Storing " + num_rec_notes + " recorded notes as layer '" + save_name +"'");
368 //console.log("**** saved: " + JSON.stringify(palTracks[save_name]));
369
370 //localStorage.setItem(docOID, JSON.stringify(docStorage));
371
372 }
373 else {
374 //console.log("Warning: unable to save '" + save_name +"' as browser does not support LocalStorage");
375 }
376
377 saveDocStorage("saveRecording()");
378
379 var cb_name = save_name.replace(/[ -]/g,"");
380 var cb_value = save_name;
381 var name = save_name;
382
383 $('#palList').append('<div id="pal'+cb_name+'"><input type="checkbox" '
384 + '" name="'+cb_name+'" value="' + cb_value + '"'
385 + ' checked="checked">'
386 + name + '</div>');
387
388 var $dialog = $('#save-recording-popup');
389 $dialog.dialog( "close" );
390 }
391
392 return valid;
393}
394
395
396function saveNewOverlay()
397{
398 var valid = true;
399
400 var $save_name_input = $("#create-info-name");
401 var save_name = $save_name_input.val();
402
403 if (save_name.match(/^\s*$/)) {
404 valid = false;
405 $save_name_input.addClass( "ui-state-error" );
406 }
407 else {
408
409 if (hasLocalStorage) {
410 var docOID = gs.cgiParams.d;
411
412
413 // Force reset of what has been stored for this item
414 //localStorage.setItem(docOID, JSON.stringify(null));
415
416 var docStorage = getDocStorage(docOID);
417
418 var popTracks = getPopTracks(docOID);
419
420 var template_webvtt;
421 template_webvtt = "WEBVTT\n";
422 template_webvtt += "\n";
423 template_webvtt += "NOTE Example Popup Info Nugget\n";
424 template_webvtt += "\n";
425 template_webvtt += "CueId1\n";
426 template_webvtt += "00:00.000 --> 00:2.000\n";
427 template_webvtt += "{\n";
428 template_webvtt += "\"title\": \"My First Title\",\n";
429 template_webvtt += "\"text\": \"My first info nugget text\",\n";
430 template_webvtt += "\"xpos\": \"10px\",\n";
431 template_webvtt += "\"ypos\": \"30px\"\n";
432 template_webvtt += "}\n";
433 template_webvtt += "\n";
434
435 popTracks[save_name] = [ template_webvtt ]; // Set up new entry, with exemplar webVTT entry
436
437 //console.log("Storing " + num_rec_notes + " recorded notes as layer '" + save_name +"'");
438 //console.log("**** saved: " + JSON.stringify(palTracks[save_name]));
439
440 //localStorage.setItem(docOID, JSON.stringify(docStorage));
441
442 }
443 else {
444 //console.log("Warning: unable to save '" + save_name +"' as browser does not support LocalStorage");
445 }
446
447 //console.log("***### pop mode, skipping saving for now");
448 saveDocStorage("saveNewOverlay()");
449
450 var cb_name = save_name.replace(/[ -]/g,"");
451 var cb_value = save_name;
452 var name = save_name;
453
454 $('#popList').append('<div id="pop'+cb_name+'"><input type="checkbox" '
455 + '" name="'+cb_name+'" value="' + cb_value + '"'
456 + ' checked="checked">'
457 + name + '</div>');
458
459 var $dialog = $('#create-info-popup');
460 $dialog.dialog( "close" );
461 }
462
463 return valid;
464}
465
466
467
468$(document).ready(function() {
469 // Setup dialog
470
471 var dialog = $('#save-recording-popup').dialog({
472 width : 500,
473 height: 350,
474 autoOpen: false, // Do not open on page load
475 modal: true, // Freeze the background behind the overlay
476
477 show: {
478 effect: "blind",
479 duration: 800
480 },
481 hide: {
482 effect: "blind",
483 duration: 300
484 },
485
486 buttons: {
487 "Save Recording": saveRecording,
488 Cancel: function() {
489 dialog.dialog("close");
490 }
491 },
492 close: function() {
493 form[0].reset();
494 $( "#save-recording-name" ).removeClass( "ui-state-error" );
495 }
496 });
497 dialog.parent().css("z-index",999);
498
499 var form = dialog.find( "form" ).on( "submit", function( event ) {
500 event.preventDefault();
501 });
502
503
504 var delete_dialog = $('#delete-recording-popup').dialog({
505 resizable: false,
506 autoOpen: false,
507 width: 500,
508 height:200,
509 modal: true,
510
511 show: {
512 effect: "blind",
513 duration: 800
514 },
515 hide: {
516 effect: "blind",
517 duration: 300
518 },
519
520 buttons: {
521 "Delete selected items": function() {
522 // call delete
523 palDeleteConfirmed();
524 $( this ).dialog( "close" );
525 },
526 Cancel: function() {
527 $( this ).dialog( "close" );
528 }
529 }
530 });
531 delete_dialog.parent().css("z-index",999);
532
533 var edit_dialog = $('#edit-recording-popup').dialog({
534 resizable: true,
535 autoOpen: false,
536 width: 800,
537 height:600,
538 modal: true,
539
540 show: {
541 effect: "blind",
542 duration: 800
543 },
544 hide: {
545 effect: "blind",
546 duration: 300
547 },
548
549 buttons: {
550 "Save": function() {
551 // call delete
552 palSave();
553 $( this ).dialog( "close" );
554 },
555 Cancel: function() {
556 $( this ).dialog( "close" );
557 }
558 }
559 });
560 edit_dialog.parent().css("z-index",999);
561
562 trackEditor = ace.edit("trackEditor");
563 trackEditor.getSession().setMode("ace/mode/json");
564 trackEditor.getSession().setUseSoftTabs(false);
565 var UndoManager = require("ace/undomanager").UndoManager;
566 trackEditor.getSession().setUndoManager(new UndoManager());
567
568 //
569 // Pop layer overlays
570 //
571
572 var new_info_dialog = $('#create-info-popup').dialog({
573 width : 500,
574 height: 350,
575 autoOpen: false, // Do not open on page load
576 modal: true, // Freeze the background behind the overlay
577
578 show: {
579 effect: "blind",
580 duration: 800
581 },
582 hide: {
583 effect: "blind",
584 duration: 300
585 },
586
587 buttons: {
588 "Create Overlay": saveNewOverlay,
589 Cancel: function() {
590 $(this).dialog("close");
591 }
592 },
593 close: function() {
594 form[0].reset();
595 $( "#create-info-name" ).removeClass( "ui-state-error" );
596 }
597 });
598 new_info_dialog.parent().css("z-index",999);
599
600 var info_delete_dialog = $('#delete-info-popup').dialog({
601 resizable: false,
602 autoOpen: false,
603 width: 500,
604 height:200,
605 modal: true,
606
607 show: {
608 effect: "blind",
609 duration: 800
610 },
611 hide: {
612 effect: "blind",
613 duration: 300
614 },
615
616 buttons: {
617 "Delete selected items": function() {
618 // call delete
619 popDeleteConfirmed();
620 $( this ).dialog( "close" );
621 },
622 Cancel: function() {
623 $( this ).dialog( "close" );
624 }
625 }
626 });
627 info_delete_dialog.parent().css("z-index",999);
628
629
630 var info_edit_dialog = $('#edit-info-popup').dialog({
631 resizable: true,
632 autoOpen: false,
633 width: 800,
634 height:600,
635 modal: true,
636
637 show: {
638 effect: "blind",
639 duration: 800
640 },
641 hide: {
642 effect: "blind",
643 duration: 300
644 },
645
646 buttons: {
647 "Save": function() {
648 // call delete
649 popSave();
650 $( this ).dialog( "close" );
651 },
652 Cancel: function() {
653 $( this ).dialog( "close" );
654 }
655 }
656 });
657 info_edit_dialog.parent().css("z-index",999);
658
659 infoEditor = ace.edit("infoEditor");
660 infoEditor.getSession().setMode("ace/mode/text");
661 infoEditor.getSession().setUseSoftTabs(false);
662 var InfoUndoManager = require("ace/undomanager").UndoManager;
663 infoEditor.getSession().setUndoManager(new UndoManager());
664
665
666
667
668
669});
670
Note: See TracBrowser for help on using the repository browser.