Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

playback.js 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. /*
  2. BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
  3. Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
  4. This program is free software; you can redistribute it and/or modify it under the
  5. terms of the GNU Lesser General Public License as published by the Free Software
  6. Foundation; either version 3.0 of the License, or (at your option) any later
  7. version.
  8. BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
  9. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  10. PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License along
  12. with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
  13. */
  14. goToSlide = function(time) {
  15. var pop = Popcorn("#video");
  16. pop.currentTime(time);
  17. }
  18. getUrlParameters = function() {
  19. var map = {};
  20. var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
  21. map[key] = value;
  22. });
  23. return map;
  24. }
  25. /*
  26. * From: http://stackoverflow.com/questions/1634748/how-can-i-delete-a-query-string-parameter-in-javascript/4827730#4827730
  27. */
  28. removeUrlParameter = function(url, param) {
  29. var urlparts= url.split('?');
  30. if (urlparts.length>=2) {
  31. var prefix= encodeURIComponent(param)+'=';
  32. var pars= urlparts[1].split(/[&;]/g);
  33. for (var i=pars.length; i-- > 0;) {
  34. if (pars[i].indexOf(prefix, 0)==0)
  35. pars.splice(i, 1);
  36. }
  37. if (pars.length > 0) {
  38. return urlparts[0]+'?'+pars.join('&');
  39. } else {
  40. return urlparts[0];
  41. }
  42. } else {
  43. return url;
  44. }
  45. }
  46. /*
  47. * Converts seconds to HH:MM:SS
  48. * From: http://stackoverflow.com/questions/6312993/javascript-seconds-to-time-with-format-hhmmss#6313008
  49. */
  50. secondsToHHMMSS = function(secs) {
  51. var hours = Math.floor(secs / 3600);
  52. var minutes = Math.floor((secs - (hours * 3600)) / 60);
  53. var seconds = secs - (hours * 3600) - (minutes * 60);
  54. if (hours < 10) {hours = "0"+hours;}
  55. if (minutes < 10) {minutes = "0"+minutes;}
  56. if (seconds < 10) {seconds = "0"+seconds;}
  57. var time = hours+':'+minutes+':'+seconds;
  58. return time;
  59. }
  60. secondsToYouTubeFormat = function(secs) {
  61. var hours = Math.floor(secs / 3600);
  62. var minutes = Math.floor((secs - (hours * 3600)) / 60);
  63. var seconds = secs - (hours * 3600) - (minutes * 60);
  64. var time = "";
  65. if (hours > 0) {time += hours+"h";}
  66. if (minutes > 0) {time += minutes+"m";}
  67. if (seconds > 0) {time += seconds+"s";}
  68. return time;
  69. }
  70. /*
  71. * Full word version of the above function for screen readers
  72. */
  73. secondsToHHMMSSText = function(secs) {
  74. var hours = Math.floor(secs / 3600);
  75. var minutes = Math.floor((secs - (hours * 3600)) / 60);
  76. var seconds = secs - (hours * 3600) - (minutes * 60);
  77. var time = "";
  78. if (hours > 1) {time += hours + " hours ";}
  79. else if (hours == 1) {time += hours + " hour ";}
  80. if (minutes > 1) {time += minutes + " minutes ";}
  81. else if (minutes == 1) {time += minutes + " minute ";}
  82. if (seconds > 1) {time += seconds + " seconds ";}
  83. else if (seconds == 1) {time += seconds + " second ";}
  84. return time;
  85. }
  86. replaceTimeOnUrl = function(secs) {
  87. var newUrl = removeUrlParameter(document.URL, "t") + "&t=" + secondsToYouTubeFormat(secs);
  88. window.history.replaceState({}, "", newUrl);
  89. }
  90. var params = getUrlParameters();
  91. var MEETINGID = params['meetingId'];
  92. var RECORDINGS = "/presentation/" + MEETINGID;
  93. var SLIDES_XML = RECORDINGS + '/slides_new.xml';
  94. var SHAPES_SVG = RECORDINGS + '/shapes.svg';
  95. /*
  96. * Sets the title attribute in a thumbnail.
  97. */
  98. setTitleOnThumbnail = function($thumb) {
  99. var src = $thumb.attr("src")
  100. if (src !== undefined) {
  101. var num = "?";
  102. var name = "undefined";
  103. var match = src.match(/slide-(.*).png/)
  104. if (match) { num = match[1]; }
  105. match = src.match(/([^/]*)\/slide-.*\.png/)
  106. if (match) { name = match[1]; }
  107. $thumb.attr("title", name + " (" + num + ")")
  108. }
  109. }
  110. /*
  111. * Associates several events on a thumbnail, e.g. click to change slide,
  112. * mouse over/out functions, etc.
  113. */
  114. setEventsOnThumbnail = function($thumb) {
  115. // Popcorn event to mark a thumbnail when its slide is being shown
  116. var timeIn = $thumb.attr("data-in");
  117. var timeOut = $thumb.attr("data-out");
  118. var pop = Popcorn("#video");
  119. pop.code({
  120. start: timeIn,
  121. end: timeOut,
  122. onStart: function( options ) {
  123. $parent = $("#thumbnail-" + options.start).parent();
  124. $parent.addClass("active");
  125. $(".thumbnail-label", $parent).show();
  126. animateToCurrentSlide();
  127. },
  128. onEnd: function( options ) {
  129. $parent = $("#thumbnail-" + options.start).parent();
  130. $parent.removeClass("active");
  131. $(".thumbnail-label", $parent).hide();
  132. }
  133. });
  134. // Click on thumbnail changes the slide in popcorn
  135. $thumb.parent().on("click", function() {
  136. goToSlide($thumb.attr("data-in"));
  137. replaceTimeOnUrl($thumb.attr("data-in"));
  138. });
  139. // Mouse over/out to show/hide the label over the thumbnail
  140. $wrapper = $thumb.parent();
  141. $wrapper.on("mouseover", function() {
  142. $(".thumbnail-label", $(this)).show();
  143. });
  144. $wrapper.on("mouseout", function() {
  145. if (!$(this).hasClass("active")) {
  146. $(".thumbnail-label", $(this)).hide();
  147. }
  148. });
  149. }
  150. $("input[name='autoscrollEnabled']").live('change', function() {
  151. animateToCurrentSlide();
  152. });
  153. animateToCurrentSlide = function(force) {
  154. force = typeof force !== 'undefined' ? force : false;
  155. if (force || isAutoscrollEnabled()) {
  156. var currentSlide = getCurrentSlide();
  157. // animate the scroll of thumbnails to center the current slide
  158. var thumbnailOffset = currentSlide.prop('offsetTop') - $("#thumbnails").prop('offsetTop') + (currentSlide.prop('offsetHeight') - $("#thumbnails").prop('offsetHeight')) / 2;
  159. $("#thumbnails").animate({ scrollTop: thumbnailOffset }, 'slow');
  160. }
  161. }
  162. isAutoscrollEnabled = function() {
  163. return $("input[name='autoscrollEnabled']").is(':checked');
  164. }
  165. setAutoscrollEnabled = function(value) {
  166. $('input[name=autoscrollEnabled]').attr('checked', value);
  167. }
  168. getCurrentSlide = function() {
  169. return $(".thumbnail-wrapper.active");
  170. }
  171. /*
  172. * Generates the list of thumbnails using shapes.svg
  173. */
  174. generateThumbnails = function() {
  175. var xmlhttp;
  176. if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
  177. xmlhttp = new XMLHttpRequest();
  178. } else {// code for IE6, IE5
  179. xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  180. }
  181. xmlhttp.open("GET", SHAPES_SVG, false);
  182. xmlhttp.send(null);
  183. if (xmlhttp.responseXML)
  184. var xmlDoc = xmlhttp.responseXML;
  185. else {
  186. var parser = new DOMParser();
  187. var xmlDoc = parser.parseFromString(xmlhttp.responseText, "image/svg+xml");
  188. }
  189. var elementsMap = {};
  190. var imagesList = new Array();
  191. xmlList = xmlDoc.getElementsByTagName("image");
  192. var slideCount = 0;
  193. for (var i = 0; i < xmlList.length; i++) {
  194. var element = xmlList[i];
  195. if (!$(element).attr("xlink:href"))
  196. continue;
  197. var src = RECORDINGS + "/" + element.getAttribute("xlink:href");
  198. if (src.match(/\/presentation\/.*slide-.*\.png/)) {
  199. var timeInList = xmlList[i].getAttribute("in").split(" ");
  200. var timeOutList = xmlList[i].getAttribute("out").split(" ");
  201. for (var j = 0; j < timeInList.length; j++) {
  202. var timeIn = Math.floor(timeInList[j]);
  203. var timeOut = Math.floor(timeOutList[j]);
  204. var img = $(document.createElement('img'));
  205. img.attr("src", src);
  206. img.attr("id", "thumbnail-" + timeIn);
  207. img.attr("data-in", timeIn);
  208. img.attr("data-out", timeOut);
  209. img.addClass("thumbnail");
  210. img.attr("alt", " ");
  211. img.attr("aria-hidden", "true"); //doesn't need to be focusable for blind users
  212. // a label with the time the slide starts
  213. var label = $(document.createElement('span'));
  214. label.addClass("thumbnail-label");
  215. label.attr("aria-hidden", "true"); //doesn't need to be focusable for blind users
  216. label.html(secondsToHHMMSS(timeIn));
  217. var hiddenDesc = $(document.createElement('span'));
  218. hiddenDesc.attr("id", img.attr("id") + "description");
  219. hiddenDesc.attr("class", "visually-hidden");
  220. hiddenDesc.html("Slide " + ++slideCount + " " + secondsToHHMMSSText(timeIn));
  221. // a wrapper around the img and label
  222. var div = $(document.createElement('div'));
  223. div.addClass("thumbnail-wrapper");
  224. div.attr("role", "link"); //tells accessibility software it can be clicked
  225. div.attr("aria-describedby", img.attr("id") + "description");
  226. div.append(img);
  227. div.append(label);
  228. div.append(hiddenDesc);
  229. imagesList.push(timeIn);
  230. elementsMap[timeIn] = div;
  231. setEventsOnThumbnail(img);
  232. setTitleOnThumbnail(img);
  233. }
  234. }
  235. }
  236. imagesList.sort(function(a,b){return a - b});
  237. for (var i in imagesList) {
  238. $("#thumbnails").append(elementsMap[imagesList[i]]);
  239. }
  240. }
  241. google_frame_warning = function(){
  242. var message = "To support this playback please install 'Google Chrome Frame', or use other browser: Firefox, Safari, Chrome, Opera";
  243. var line = document.createElement("p");
  244. var link = document.createElement("a");
  245. line.appendChild(document.createTextNode(message));
  246. link.setAttribute("href", "http://www.google.com/chromeframe")
  247. link.setAttribute("target", "_blank")
  248. link.appendChild(document.createTextNode("Install Google Chrome Frame"));
  249. document.getElementById("chat").appendChild(line);
  250. document.getElementById("chat").appendChild(link);
  251. }
  252. function checkUrl(url)
  253. {
  254. console.log("Checking Url")
  255. var http = new XMLHttpRequest();
  256. http.open('HEAD', url, false);
  257. http.send();
  258. return http.status==200;
  259. }
  260. load_video = function(){
  261. console.log("Loading video")
  262. //document.getElementById("video").style.visibility = "hidden"
  263. var video = document.createElement("video")
  264. video.setAttribute('id','video');
  265. video.setAttribute('class','webcam');
  266. var webmsource = document.createElement("source");
  267. webmsource.setAttribute('src', RECORDINGS + '/video/webcams.webm');
  268. webmsource.setAttribute('type','video/webm; codecs="vp8.0, vorbis"');
  269. video.appendChild(webmsource);
  270. /*var time_manager = Popcorn("#video");
  271. var pc_webcam = Popcorn("#webcam");
  272. time_manager.on( "timeupdate", function() {
  273. pc_webcam.currentTime( this.currentTime() );
  274. });*/
  275. video.setAttribute('data-timeline-sources', SLIDES_XML);
  276. //video.setAttribute('controls','');
  277. //leave auto play turned off for accessiblity support
  278. //video.setAttribute('autoplay','autoplay');
  279. document.getElementById("videoRecordingWrapper").appendChild(video);
  280. }
  281. load_audio = function() {
  282. console.log("Loading audio")
  283. var audio = document.createElement("audio") ;
  284. audio.setAttribute('id', 'video');
  285. // The webm file will work in IE with WebM components installed,
  286. // and should load faster in Chrome too
  287. var webmsource = document.createElement("source");
  288. webmsource.setAttribute('src', RECORDINGS + '/audio/audio.webm');
  289. webmsource.setAttribute('type', 'audio/webm; codecs="vorbis"');
  290. // Need to keep the ogg source around for compat with old recordings
  291. var oggsource = document.createElement("source");
  292. oggsource.setAttribute('src', RECORDINGS + '/audio/audio.ogg');
  293. oggsource.setAttribute('type', 'audio/ogg; codecs="vorbis"');
  294. // Browser Bug Workaround: The ogg file should be preferred in Firefox,
  295. // since it can't seek in audio-only webm files.
  296. if (navigator.userAgent.indexOf("Firefox") != -1) {
  297. audio.appendChild(oggsource);
  298. audio.appendChild(webmsource);
  299. } else {
  300. audio.appendChild(webmsource);
  301. audio.appendChild(oggsource);
  302. }
  303. audio.setAttribute('data-timeline-sources', SLIDES_XML);
  304. //audio.setAttribute('controls','');
  305. //leave auto play turned off for accessiblity support
  306. //audio.setAttribute('autoplay','autoplay');
  307. document.getElementById("audioRecordingWrapper").appendChild(audio);
  308. }
  309. load_script = function(file){
  310. console.log("Loading script "+ file)
  311. script = document.createElement('script');
  312. script.src = file;
  313. script.type = 'text/javascript';
  314. document.getElementsByTagName('body').item(0).appendChild(script);
  315. }
  316. document.addEventListener( "DOMContentLoaded", function() {
  317. var appName = navigator.appName;
  318. var appVersion = navigator.appVersion;
  319. //var video = document.getElementById("webcam");
  320. if (appName == "Microsoft Internet Explorer" && navigator.userAgent.match("chromeframe") == false ) {
  321. google_frame_warning
  322. }
  323. if (checkUrl(RECORDINGS + '/video/webcams.webm') == true){
  324. videoContainer = document.getElementById("audioRecordingWrapper").style.display = "none";
  325. load_video();
  326. }else{
  327. videoContainer = document.getElementById("videoRecordingWrapper").style.display = "none";
  328. chat = document.getElementById("chat");
  329. chat.style.height = "600px";
  330. chat.style.backgroundColor = "white";
  331. load_audio();
  332. }
  333. //load_audio();
  334. load_script("lib/writing.js");
  335. //generateThumbnails();
  336. //load up the acorn controls
  337. jQuery('#video').acornMediaPlayer({
  338. theme: 'darkglass',
  339. volumeSlider: 'vertical'
  340. });
  341. }, false);
  342. var secondsToWait = 0;
  343. function addTime(time){
  344. if (secondsToWait === 0) {
  345. Popcorn('#video').pause();
  346. window.setTimeout("Tick()", 1000);
  347. }
  348. secondsToWait += time;
  349. }
  350. function Tick() {
  351. if (secondsToWait <= 0 || !($("#accEnabled").is(':checked'))) {
  352. secondsToWait = 0;
  353. Popcorn('#video').play();
  354. $('#countdown').html(""); // remove the timer
  355. return;
  356. }
  357. secondsToWait -= 1;
  358. $('#countdown').html(secondsToWait);
  359. window.setTimeout("Tick()", 1000);
  360. }