plugin detection created as a widget; can't tell yet if swarmplayer is installed
[living-lab-site.git] / js / jquery.ui.nsvideo.js
1 /*
2  * jQuery UI NS-Video 1.0.0 beta
3  *
4  * Copyright 2011, Călin-Andrei Burloiu
5  * Dual licensed under the MIT or GPL Version 2 licenses.
6  * http://jquery.org/license
7  *
8  *
9  * Depends:
10  *   jquery.ui.core.js
11  *   jquery.ui.widget.js
12  */
13 (function( $, undefined ) {
14
15 $.widget( "ui.nsvideo", {
16         version: "1.0.0 beta",
17         options: {
18                 type: 'ns-html5',
19                 srcIndex: 0,
20                 width: 0,
21                 height: 0,
22                 minWidth: 0,
23                 maxWidth: 0,
24                 showState: true,
25                 refreshInterval: 0.1,   // seconds
26                 autoplay: false,
27                 initialDuration: "--:--"
28         },
29         
30         _create: function() {
31                 var widget = this;
32                 
33                 widget.element
34                         .addClass( "ui-widget ui-widget-content ui-corner-all" );
35                 
36                 widget.$videoContainer = $('<div class="ui-nsvideo-nsplugin"></div>')
37                         .appendTo(widget.element);
38                 widget.$progressContainer = $('<div class="ui-nsvideo-progress-container ui-widget-content ui-corner-top"></div>')
39                         .appendTo(widget.element);
40                 widget.$progress = $('<div class="ui-nsvideo-progress"></div>')
41                         .appendTo(widget.$progressContainer);
42                 widget.$loadedProgress = $('<div class="ui-nsvideo-loaded-progress"></div>')
43                         .appendTo(widget.$progress);
44                 widget.$controls = $('<div class="ui-nsvideo-controls ui-widget-content ui-corner-bottom"></div>')
45                         .appendTo(widget.element);
46                 
47                 widget.video();
48                 
49                 // Time progress slider with load progress also
50                 widget.$loadedProgress
51                         // TODO an object that inherits progressbar should be used in order to customize min value.
52                         .progressbar({
53                                 value: 0
54                         });
55                 widget.$progress
56                         .slider({
57                                         value: 0,
58                                         min: 0,
59                                         max: 1000,
60                                         slide: function(event, ui) {
61                                                 widget.videoPlugin('crtTime', [ui.value]);
62                                                 widget.videoPlugin('refreshTime');
63                                                 widget.videoPlugin('refreshState');
64                                         }
65                         });
66                 
67                 // Play / Pause
68                 $('<button class="ui-nsvideo-play ui-nsvideo-button ui-nsvideo-control-left">Play / Pause</button>')
69                         .appendTo(widget.$controls)
70                         .button({
71                                 text: false,
72                                 icons: { primary: "ui-icon-play" }
73                         })
74                         .click(function() {
75                                 widget.videoPlugin('togglePlay');
76                         });
77                 
78                 // Time information (current and total)
79                 widget.$time = $('<div class="ui-nsvideo-time ui-nsvideo-text ui-nsvideo-control-left">00:00 / ' + widget.options.initialDuration + '</div>')
80                         .appendTo(widget.$controls);
81                         
82                 // Full screen
83                 $('<button class="ui-nsvideo-fullscreen ui-nsvideo-button ui-nsvideo-control-right">Full Screen</button>')
84                         .appendTo(widget.$controls)
85                         .button({
86                                 text: false,
87                                 icons: { primary: "ui-icon-arrow-4-diag" }
88                         })
89                         .click(function() {
90                                 widget.videoPlugin('fullscreen');
91                         });
92
93                 // Video format buttonset
94                 if (typeof widget.options.src == 'object')
95                 {
96                         var $formats = $('<form><div class="ui-nsvideo-formats ui-nsvideo-control-right"></div></form>')
97                                 .appendTo(widget.$controls);
98                         $formats = $('.ui-nsvideo-formats', $formats[0]);
99                         $.each(widget.options.src, function(index, value) {
100                                 id = widget.element.attr('id') + '-format-' + index;
101                                 definition = value.res.substring(value.res.indexOf('x')+1)+'p';
102                                 $('<input type="radio" id="' + id + '" name="format" />')
103                                         .appendTo($formats)
104                                         .attr('checked', (index == widget.options.srcIndex))
105                                         .click(function() {
106                                                 widget.videoPlugin('pause');
107                                                 widget.srcIndex(index);
108                                         });
109                                 $('<label for="' + id + '">' + definition + '</label>')
110                                         .appendTo($formats);
111                         });
112                         
113                         $formats.buttonset();
114                 }
115                 
116                 // Volume
117                 $('<div class="ui-nsvideo-volume ui-nsvideo-control-right"></div>')
118                         .appendTo(widget.$controls)
119                         .slider({
120                                 range: "min",
121                                 min: 0,
122                                 max: 100,
123                                 slide: function(event, ui) {
124                                         widget.videoPlugin('volume', [ui.value]);
125                                 }
126                         });
127                 
128                 // Toggle Mute
129                 $('<button class="ui-nsvideo-mute ui-nsvideo-button ui-nsvideo-control-right">Mute</button>')
130                         .appendTo(widget.$controls)
131                         .button({
132                                 text: false,
133                                 icons: { primary: "ui-icon-volume-on" }
134                         })
135                         .click(function() {
136                                 widget.videoPlugin('toggleMute');
137                         });
138                         
139                 // Status information
140                 widget.$stateText = $('<div class="ui-nsvideo-text ui-nsvideo-control-right">...</div>')
141                         .appendTo(widget.$controls)
142                         .css('cursor', 'pointer')
143                         .click(function() {
144                                 widget.videoPlugin('refreshAll');
145                         });
146                 if (! widget.options.showState)
147                         widget.$stateText.hide();
148                 
149                 // Clear fix helper
150                 $('<div class="ui-helper-clearfix"></div>')
151                         .appendTo(widget.$controls);
152         },
153
154         _destroy: function() {
155                 
156         },
157
158         _setOption: function( key, value ) {
159                 // TODO
160                 if ( key === "TODO" ) {
161                         
162                 }
163
164                 this._super( "_setOption", key, value );
165         },
166         
167         _leadingZeros: function(number, length) {
168                 if (!length)
169                         length = 2;
170                 
171                 var str = '';
172                 
173                 if (isNaN(number))
174                 {
175                         for (var i=0; i<length; i++)
176                                 str += '-';
177                         return str;
178                 }
179                 
180                 str += number;
181                 while (str.length < length) 
182                 {
183                         str = '0' + str;
184                 }
185
186                 return str;
187         },
188         
189         video: function() {
190                 widget = this;
191                 
192                 // Select video source.
193                 // If src option is string, that's the source.
194                 // If src is an object, there is a list of associative arrays, each
195                 // one having the mandatory keys "src" and "res" (resolution).
196                 var src = widget.crtSrc();
197                 if (src == null)
198                         return widget;
199                 
200                 widget.$videoContainer.html('');
201                 
202                 // Install buttons or not supported message if required
203                 var $installContainer = $('<div class="container-install-in-widget"></div>')
204                         .appendTo(widget.$videoContainer);
205                 $installContainer
206                         .nsinstall({
207                                 type: widget.options.type,
208                                 hideIfAlreadyInstalled: true
209                         });
210                 
211                 var width = widget.options.width;
212                 var height = widget.options.height;
213                 
214                 // HTML5
215                 if (widget.options.type == 'ns-html5'
216                         || widget.options.type == 'html5')
217                 {
218                         widget.$video = $('<video id="' + widget.element.attr('id') + '-video" src="' + src + '"' + (width == 0 ? '' : ' width="' + width + '"') + (height == 0 ? '' : ' height="' + height + '"') + ' preload="auto"' + (widget.options.autoplay ? ' autoplay="autoplay"' : '') + '>'
219                                 +'Error: Your browser does not support HTML5 or the video format!'
220                         +'</video>')
221                                 .appendTo(widget.$videoContainer)
222                                 .bind({
223                                         ended: function() {
224                                                 widget.html5.pause();
225                                                 widget.html5.refreshState();
226                                         },
227                                         play: function() {
228                                                 widget.html5.play();
229                                                 widget.html5.refreshState();
230                                         },
231                                         pause: function() {
232                                                 widget.html5.pause();
233                                                 widget.html5.refreshState();
234                                         },
235                                         timeupdate: function() {
236                                                 widget.html5.refreshTime();
237                                         },
238                                         progress: function() {
239                                                 widget.html5.refreshLoadedProgress();
240                                         },
241                                         loadedmetadata: function() {
242                                                 widget.html5.refreshTime();
243                                                 widget.html5.refreshVolume();
244                                                 widget.html5.refreshState();
245                                                 widget._setWidgetWidth();
246                                         },
247                                         seeked: function() {
248                                                 widget.html5.play();
249                                                 widget.html5.refreshState();
250                                         },
251                                         volumechange: function() {
252                                                 widget.html5.refreshVolume();
253                                         },
254                                         
255                                         loadstart: function() {
256                                                 widget.html5.refreshState();
257                                         },
258                                         suspend: function() {
259                                                 widget.html5.refreshState();
260                                         },
261                                         abort: function() {
262                                                 widget.html5.refreshState();
263                                         },
264                                         error: function() {
265                                                 widget.html5.refreshState();
266                                         },
267                                         emptied: function() {
268                                                 widget.html5.refreshState();
269                                         },
270                                         stalled: function() {
271                                                 widget.html5.refreshState();
272                                         },
273                                         loadeddata: function() {
274                                                 widget.html5.refreshState();
275                                         },
276                                         waiting: function() {
277                                                 widget.html5.refreshState();
278                                         },
279                                         seeking: function() {
280                                                 widget.html5.refreshState();
281                                         },
282                                 });
283                 }
284                 // VLC
285                 else if (widget.options.type == 'ns-vlc'
286                         || widget.options.type == 'vlc')
287                 {
288                         var embedType;
289                         if (widget.options.type == 'ns-vlc')
290                                 embedType = 'application/x-ns-stream';
291                         else
292                                 embedType = 'application/x-vlc-plugin';
293                         
294                         if (navigator.appName == "Netscape")
295                         {
296                                 widget.$video = $('<embed type="' + embedType + '" name="vlcVideo" id="' + widget.element.attr('id') + '-video" autoplay="' + (widget.options.autoplay ? 'yes' : 'no') + '" loop="no" width="' + (width == 0 ? '640' : width) + '" height="' + (height == 0 ? '480' : height) + '" target="' + src + '" />')
297                                         .appendTo(widget.$videoContainer);
298                         }
299                         else
300                         {
301                                 widget.$video = $('<object classid="clsid:1800B8AF-4E33-43C0-AFC7-894433C13538" width="' + (width == 0 ? '640' : width) + '" height="' + (height == 0 ? '480' : height) + '" id="' + widget.element.attr('id') + '-video" name="vlcVideo" events="True" target="">'
302                                                 + '<param name="Src" value="' + src + '" />'
303                                                 + '<param name="ShowDisplay" value="True" />'
304                                                 + '<param name="Loop" value="False" />'
305                                                 + '<param name="AutoPlay" value="' + (widget.options.autoplay ? 'True' : 'False') + '" />'
306                                                 + '<param name="Toolbar" value="False" />'
307                                         + '</object>')
308                                         .appendTo(widget.$videoContainer);
309                         }
310                 }
311                 
312                 //  BUG: this if is because of a NS-VLC bug.
313                 if (widget.options.type != 'ns-vlc')
314                         widget.$video.css('position', 'relative');
315                 
316                 // Adjust video size for auto-resizing within ranges minWidth and
317                 // maxWidth.
318                 if ( (width == 0 || height == 0)
319                         && (widget.options.minWidth != 0 && widget.options.maxWidth != 0
320                                 || this.options.type.indexOf('vlc') != -1) )
321                 {
322                         widget.adjustVideoSizeFromMeta();
323                 }
324                 
325                 // Initialize video plugin
326                 widget.$video.ready(function() {
327                         widget.videoPlugin('init');
328                 });
329                 
330                 widget._setWidgetWidth();
331         },
332         
333         adjustVideoSizeFromMeta: function() {
334                 var widget = this;
335                 
336                 if (typeof widget.options.src == 'object'
337                         && (typeof widget.options.src[ widget.options.srcIndex ].res)
338                                 != 'undefined'
339                         && (typeof widget.options.src[ widget.options.srcIndex ].dar)
340                                 != 'undefined')
341                 {
342                         var resolution = widget.options.src[ widget.options.srcIndex ].res;
343                         var dar = widget.options.src[ widget.options.srcIndex ].dar;
344                         var darL = parseInt(
345                                 dar.substring(0, dar.indexOf(':')));
346                         var darR = parseInt(
347                                 dar.substring(dar.indexOf(':') + 1));
348                         var videoHeight = parseInt(
349                                 resolution.substring(resolution.indexOf('x') + 1));
350                         var videoWidth = Math.round(videoHeight * darL / darR);
351                         
352                         // Video width must be between minWidth and maxWidth pixels.
353                         if (widget.options.minWidth != 0 && widget.options.maxWidth != 0)
354                         {
355                                 if (videoWidth > widget.options.maxWidth)
356                                 {
357                                         videoHeight = Math.round(widget.options.maxWidth / videoWidth
358                                                 * videoHeight);
359                                         videoWidth = widget.options.maxWidth;
360                                 }
361                                 else if (videoWidth < widget.options.minWidth)
362                                 {
363                                         videoHeight = Math.round(widget.options.minWidth / videoWidth
364                                                 * videoHeight);
365                                         videoWidth = widget.options.minWidth;
366                                 }
367                         }
368                         
369                         widget.$video.css('width', videoWidth);
370                         widget.$video.css('height', videoHeight);
371                 }
372         },
373         
374         _setWidgetWidth: function() {
375                 if (widget.$video.width() < 640)
376                 {
377                         widget.element.css('width',
378                                                         640 + 8 + 'px');
379                         widget.$video.css('left', 
380                                 Math.round(widget.$videoContainer.width()/2 
381                                 - widget.$video.width()/2)
382                                 + 'px');
383                 }
384                 else
385                 {
386                         widget.element.css('width',
387                                                         widget.$video.width() + 8 + 'px');
388                         widget.$video.css('left', '0');
389                 }
390                 
391                 this._trigger('resize');
392         },
393         
394         setPlayButton: function() {
395                 $('button.ui-nsvideo-play', widget.element[0])
396                         .button('option', 'icons', { primary: "ui-icon-play" })
397                         .button('refresh');
398         },
399         setPauseButton: function() {
400                 $('button.ui-nsvideo-play', widget.element[0])
401                         .button('option', 'icons', { primary: "ui-icon-pause" })
402                         .button('refresh');
403         },
404         setMuteButton: function() {
405                 $('button.ui-nsvideo-mute', widget.element[0])
406                         .button('option', 'icons', { primary: "ui-icon-volume-off" })
407                         .button('refresh');
408         },
409         setUnmuteButton: function() {
410                 $('button.ui-nsvideo-mute', widget.element[0])
411                         .button('option', 'icons', { primary: "ui-icon-volume-on" })
412                         .button('refresh');
413         },
414         setTimeText: function(text) {
415                 //$('.ui-nsvideo-time', widget.element[0])
416                 this.$time
417                         .html(text);
418         },
419         setVolumeSlider: function(vol) {
420                 $('.ui-nsvideo-volume', widget.element[0])
421                         .slider('value', vol);
422         },
423         setProgressSlider: function(prog) {
424                 $('.ui-nsvideo-progress', widget.element[0])
425                         .slider('value', prog);
426         },
427         setLoadedProgressSlider: function(prog) {
428                 $('.ui-nsvideo-loaded-progress', widget.element[0])
429                         .progressbar('value', prog);
430         },
431         
432         videoPlugin: function(method, args) {
433                 if (typeof args == 'undefined')
434                         args = [];
435                 var videoPlugin = null;
436                 
437                 if (this.options.type.indexOf('html5') != -1)
438                 {
439                         videoPlugin = this.html5;
440                 }
441                 else if (this.options.type.indexOf('vlc') != -1)
442                 {
443                         videoPlugin = this.vlc;
444                 }
445                 
446                 if (videoPlugin)
447                         return videoPlugin[method].apply(this, args);
448                 
449                 return null;
450         },
451         
452         srcIndex: function(srcIndex) {
453                 var widget = this;
454                 
455                 if (typeof srcIndex == 'undefined')
456                         return widget.options.srcIndex;
457                 
458                 widget.options.srcIndex = srcIndex;
459                 
460                 // Refresh.
461                 widget.video();
462                 
463                 return widget;
464         },
465         
466         type: function(type) {
467                 var widget = this;
468                 
469                 if (typeof type == 'undefined')
470                         return widget.options.type;
471                 
472                 widget.videoPlugin('pause');
473                 if (widget.vlc.timerHandle)
474                         clearTimeout(widget.vlc.timerHandle);
475                 
476                 widget.options.type = type;
477                 widget.video();
478                 
479                 // Initialize video plugin
480                 widget.$video.ready(function() {
481                         widget.videoPlugin('init');
482                 });
483                 
484                 return widget;
485         },
486         
487         crtSrc: function() {
488                 var src;
489                 var widget = this;
490                 
491                 if (typeof widget.options.src == 'string')
492                         src = widget.options.src;
493                 else if (typeof widget.options.src == 'object')
494                 {
495                         if (typeof widget.options.srcIndex == 'undefined')
496                                 return null;
497                         
498                         if (typeof widget.options.src[ widget.options.srcIndex ].src
499                                 == 'undefined')
500                                 return null;
501                         
502                         src = widget.options.src[ widget.options.srcIndex ].src;
503                 }
504                 
505                 if (widget.options.type == 'ns-html5')
506                         src = 'tribe://' + src;
507                 
508                 return src;
509         },
510         
511         html5: {
512                 widget: this,
513                 //lastTime: null,
514                 
515                 ERR_STATES: {
516                         MEDIA_ERR_ABORTED: [1, "error: aborted"],
517                         MEDIA_ERR_NETWORK: [2, "network error"],
518                         MEDIA_ERR_DECODE: [3, "decode error"],
519                         MEDIA_ERR_SRC_NOT_SUPPORTED: [4, "error: source not supported"]
520                 },
521                 
522                 NETWORK_STATES: {
523                         NETWORK_EMPTY: [0, "no data from network"],
524                         NETWORK_IDLE: [1, ""],
525                         NETWORK_LOADING: [2, "loading..."],
526                         NETWORK_LOADED: [3, "loading completed"],
527                         NETWORK_NO_SOURCE: [4, "network: no source"]
528                 },
529                 
530                 READY_STATES: {
531                         HAVE_NOTHING: [0, "please wait..."],
532                         HAVE_METADATA: [1, ""],
533                         HAVE_CURRENT_DATA: [2, ""],
534                         HAVE_FUTURE_DATA: [3, ""],
535                         HAVE_ENOUGH_DATA: [4, "have enough data"]
536                 },
537                 
538                 init: function() {
539                         //widget.html5.refreshAll();
540                         
541                         widget.html5.refreshState();
542                         
543                         //if (widget.options.autoplay)
544                         //      widget.html5.play();
545                 },
546                 
547                 togglePlay: function() {
548                         if (widget.$video[0].paused)
549                         {
550                                 widget.html5.play();
551                         }
552                         else
553                         {
554                                 widget.html5.pause();
555                         }
556                 },
557
558                 play: function() {
559                         if (widget.$video[0].paused)
560                                 widget.$video[0].play();
561                         
562                         widget.setPauseButton();
563                         
564                         return widget;
565                 },
566                 
567                 pause: function() {
568                         if (!widget.$video[0].paused)
569                                 widget.$video[0].pause();
570                         
571                         widget.setPlayButton();
572
573                         return widget;
574                 },
575                 
576                 toggleMute: function() {
577                         if (!widget.$video[0].muted)
578                         {
579                                 widget.html5.mute();
580                         }
581                         else
582                         {
583                                 widget.html5.unmute();
584                         }
585                 },
586                   
587                 mute: function() {
588                         if (!widget.$video[0].muted)
589                                 widget.$video[0].muted = true;
590                         
591                         widget.setMuteButton();
592                         
593                         return widget;
594                 },
595                 
596                 unmute: function() {
597                         if (widget.$video[0].muted)
598                                 widget.$video[0].muted = false;
599                         
600                         widget.setUnmuteButton();
601                         
602                         return widget;
603                 },
604                 
605                 /**
606                 * Volume value is expressed in percents.
607                 */
608                 volume: function(vol) {
609                         if (typeof vol == 'undefined')
610                                 return Math.round(widget.$video[0].volume * 100);
611                         
612                         widget.html5.unmute();
613                         widget.$video[0].volume = vol / 100;
614                         
615                         return widget;
616                 },
617                 
618                 /**
619                  * Seek position is a value between 0 and 1000.
620                  */
621                 crtTime: function(pos) {
622                         // getter
623                         if (typeof pos == 'undefined')
624                         {
625                                 var crtTime = widget.$video[0].currentTime;
626                                 var totTime = widget.$video[0].duration;
627                                 if (isNaN(totTime) || totTime == 0)
628                                         return 0;
629                                 else
630                                         return Math.round(crtTime / totTime * 1000.0);
631                         }
632                         
633                         // setter
634                         widget.$video[0].currentTime = 
635                                 pos / 1000 * widget.$video[0].duration;
636                 },
637                   
638                 refreshAll: function() {
639                         widget.html5.refreshState();
640                         widget.html5.refreshVolume();
641                         widget.html5.refreshLoadedProgress();
642                         widget.html5.refreshTime();
643                 },
644                 
645                 refreshTime: function() {
646                         if (widget.$video[0].seeking)
647                                 return widget;
648                         
649                         var crtTime = widget.$video[0].currentTime;
650                         var totTime = widget.$video[0].duration;
651                         
652                         // Refresh only at refreshInterval seconds to save CPU time.
653                         var delta = crtTime - widget.html5.lastTime;
654                         if (typeof widget.html5.lastTime !== "undefined"
655                                 && delta >= 0 && delta < widget.options.refreshInterval)
656                                 return widget;
657                         widget.html5.lastTime = crtTime;
658                         
659                         // Current time string
660                         var crtH = Math.floor(crtTime / 3600);
661                         var crtM = Math.floor((crtTime / 60) % 60);
662                         var crtS = Math.floor(crtTime % 60);
663                         var strCrtTime = 
664                                 (crtH == 0 ? '' : (widget._leadingZeros(crtH) + ':'))
665                                 + widget._leadingZeros(crtM) + ':' + widget._leadingZeros(crtS);
666                                 
667                         // Total time string
668                         var totH = Math.floor(totTime / 3600);
669                         var totM = Math.floor((totTime / 60) % 60);
670                         var totS = Math.floor(totTime % 60);
671                         var strTotTime = 
672                                 (totH == 0 || isNaN(totH) ? '' : (widget._leadingZeros(totH) + ':'))
673                                 + widget._leadingZeros(totM) + ':' + widget._leadingZeros(totS);
674                         
675                         widget.setTimeText('' + strCrtTime + ' / ' + strTotTime);
676                         
677                         // Update time progress slider.
678                         widget.html5.refreshProgress();
679                         
680                         return widget;
681                 },
682                 
683                 _state: function(type, code) {
684                         var r;
685                         $.each(widget.html5[type + '_STATES'], function(index, value) {
686                                 if ('' + code == '' + value[0])
687                                 {
688                                         r = value;
689                                         return false;
690                                 }
691                         });
692                         
693                         return r;
694                 },
695                 
696                 refreshState: function() {
697                         var err = "";
698                         var normal = "";
699                         var network = "";
700                         var ready = "";
701                         var state = "";
702                         
703                         if (widget.$video[0].error)
704                                 err = widget.html5._state('ERR',
705                                                                                   widget.$video[0].error.code)[1];
706                           
707                         if (! widget.$video[0].paused)
708                                 normal = "playing...";
709                         else
710                         {
711                                 normal = "paused";
712                         }
713                         if (widget.$video[0].seeking)
714                                 normal = "seeking";
715                         if (widget.$video[0].ended)
716                                 normal = "ended";
717                         
718                         network = widget.html5._state('NETWORK',
719                                                                         widget.$video[0].networkState)[1]; 
720                         
721                         ready = widget.html5._state('READY',
722                                                                         widget.$video[0].readyState)[1];
723                         
724                         if (err !== "")
725                                 state = err;
726                         else
727                         {
728                                 state = normal;
729                                 
730                                 if (normal !== "" && (network !== "" || ready !== "") )
731                                         state += ' / ';
732                                 
733                                 if (network !== "")
734                                         state += network;
735                                 
736                                 if (network !== "" && ready !== "")
737                                         state += ' / ';
738                                 
739                                 if (ready !== "")
740                                         state += ready;
741                         }
742                         
743                         widget.$stateText
744                                 .html(state);
745                         
746                         return widget;
747                 },
748
749                 refreshVolume: function() {
750                         var vol;
751                         
752                         if (widget.$video[0].muted)
753                                 vol = 0;
754                         else
755                                 vol = Math.floor(widget.$video[0].volume * 100);
756                         
757                         widget.setVolumeSlider(vol);
758                         
759                         return widget;
760                 },
761                 
762                 refreshProgress: function() {
763                         widget.setProgressSlider(widget.html5.crtTime());
764                         
765                         return widget;
766                 },
767                 
768                 /**
769                 * Supported for Firefox 4.0 or later.
770                 */
771                 refreshLoadedProgress: function() {
772                         // Return if buffering status not available in browser.
773                         if (typeof widget.$video[0].buffered == 'undefined'
774                                 || widget.$video[0].buffered.length === 0)
775                                 return widget;
776                         
777                         var loadedTime = widget.$video[0].buffered.end(0);
778                         var totTime = widget.$video[0].duration;
779                         var percent;
780                         if (isNaN(totTime) || totTime == 0)
781                                 percent = 0
782                         else
783                                 percent = Math.floor(loadedTime / totTime * 100);
784                         
785                         widget.setLoadedProgressSlider(percent);
786                         
787                         return widget;
788                 },
789
790                 fullscreen: function() {
791                         alert('Your web browser does not support switching to full screen in HTML5 mode with this button. You can switch to full screen manually by right clicking on the video and choosing "Full Screen" from the popup menu.');
792                 }
793         },
794         
795         vlc: {
796                 widget: this,
797                 timerHandle: null,
798                 idleRefreshInterval: 1, // seconds
799                 
800                 STATES: {
801                         IDLE: [0, "idle"],
802                         OPENING: [1, "opening..."],
803                         BUFFERING: [2, "buffering..."],
804                         PLAYING: [3, "playing..."],
805                         PAUSED: [4, "paused"],
806                         STOPPING: [5, "stopping..."],
807                         ENDED: [6, "ended"],
808                         ERROR: [7, "error!"]
809                 },
810                 
811                 init: function() {
812                         if (widget.options.autoplay)
813                                 widget.vlc.play();
814                         widget.vlc.refreshAll();
815                 },
816                 
817                 togglePlay: function() {
818                         if (! widget.$video[0].playlist.isPlaying)
819                         {
820                                 widget.vlc.play();
821                         }
822                         else
823                         {
824                                 widget.vlc.pause();
825                         }
826                 },
827                 
828                 play: function() {
829                         if (! widget.$video[0].playlist.isPlaying)
830                                 widget.$video[0].playlist.play();
831                         
832                         widget.setPauseButton();
833                         
834                         // Schedule information refreshment at refreshInterval seconds.
835                         if (! widget.vlc.timerHandle)
836                                 widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler, 
837                                                                                 widget.options.refreshInterval * 1000);
838                                 
839                         widget.vlc.refreshState();
840                         
841                         return widget;
842                 },
843                 
844                 pause: function() {
845                         if (typeof widget.$video[0].playlist === 'undefined')
846                                 return widget;
847                         
848                         if (widget.$video[0].playlist.isPlaying)
849                                 widget.$video[0].playlist.togglePause();
850                         
851                         widget.setPlayButton();
852                         
853                         // Cancel information refreshment scheduling.
854                         clearTimeout(widget.vlc.timerHandle);
855                         widget.vlc.timerHandle = null;
856                         
857                         widget.vlc.refreshState();
858
859                         return widget;
860                 },
861                 
862                 toggleMute: function() {
863                         if (! widget.$video[0].audio.mute)
864                         {
865                                 widget.vlc.mute();
866                         }
867                         else
868                         {
869                                 widget.vlc.unmute();
870                         }
871                 },
872                   
873                 mute: function() {
874                         if (! widget.$video[0].audio.mute)
875                                 widget.$video[0].audio.toggleMute();
876                         
877                         widget.setMuteButton();
878                         
879                         widget.vlc.refreshVolume();
880                         
881                         return widget;
882                 },
883                 
884                 unmute: function() {
885                         if (widget.$video[0].audio.mute)
886                                 widget.$video[0].audio.toggleMute();
887                         
888                         widget.setUnmuteButton();
889                         
890                         widget.vlc.refreshVolume();
891                         
892                         return widget;
893                 },
894                 
895                 /**
896                 * Volume value is expressed in percents.
897                 */
898                 volume: function(vol) {
899                         if (typeof vol == 'undefined')
900                                 return Math.round(widget.$video[0].audio.volume);
901                         
902                         widget.vlc.unmute();
903                         widget.$video[0].audio.volume = vol;
904                         
905                         return widget;
906                 },
907                 
908                 /**
909                  * Seek position is a value between 0 and 1000.
910                  */
911                 crtTime: function(pos) {
912                         // getter
913                         if (typeof pos == 'undefined')
914                         {
915                                 var crtTime = widget.$video[0].input.time;
916                                 var totTime = widget.$video[0].input.length;
917                                 if (isNaN(totTime) || totTime == 0)
918                                         return 0;
919                                 else
920                                         return Math.round(crtTime / totTime * 1000.0);
921                         }
922                         
923                         // setter
924                         widget.$video[0].input.time = 
925                                 pos / 1000 * widget.$video[0].input.length;
926                                 
927                         widget.vlc.refreshState();
928                 },
929                 
930                 /**
931                  * Timeout callback called at refreshInterval during playing in order
932                  * to refresh information.
933                  */
934                 refreshHandler: function() {
935                         if (widget.$video[0].input.state
936                                 == widget.vlc.STATES.PLAYING[0])
937                         {
938                                 widget.vlc.refreshTime();
939                                 widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler, 
940                                                                                 widget.options.refreshInterval * 1000);
941                         }
942                         else
943                         {
944                                 if (widget.$video[0].input.state == widget.vlc.STATES.ENDED[0])
945                                 {
946                                         widget.vlc.pause();
947                                         try {
948                                                 widget.$video[0].playlist.stop();
949                                         } catch(e) {
950                                                 console.log('Exception: ' + e);
951                                         }
952                                 }
953                                 
954                                 widget.vlc.refreshTime();
955                                 widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler, 
956                                                                                 widget.vlc.idleRefreshInterval * 1000);
957                         }
958                         
959                         widget.vlc.refreshState();
960                 },
961                 
962                 refreshAll: function() {
963                         widget.vlc.refreshState();
964                         widget.vlc.refreshVolume();
965                         widget.vlc.refreshLoadedProgress();
966                         
967                         try {
968                                 widget.vlc.refreshTime();
969                         } catch(e) {
970                                 console.log('Exception: ' + e);
971                                 widget.$time.html('00:00 / ' + widget.options.initialDuration);
972                         }
973                 },
974                 
975                 refreshTime: function() {
976                         // TODO while seeking (maybe not necessary for VLC)
977 //                      if (widget.$video[0].seeking)
978 //                              return widget;
979                         
980                         // Time values in seconds.
981                         var crtTime = widget.$video[0].input.time / 1000.0;
982                         var totTime = widget.$video[0].input.length / 1000.0;
983                         //var crtTime = widget.$video[0].input.position * totTime;
984                         
985                         // Current time string
986                         var crtH = Math.floor(crtTime / 3600);
987                         var crtM = Math.floor((crtTime / 60) % 60);
988                         var crtS = Math.floor(crtTime % 60);
989                         var strCrtTime = 
990                                 (crtH == 0 ? '' : (widget._leadingZeros(crtH) + ':'))
991                                 + widget._leadingZeros(crtM) + ':' + widget._leadingZeros(crtS);
992                                 
993                         // Total time string
994                         var totH = Math.floor(totTime / 3600);
995                         var totM = Math.floor((totTime / 60) % 60);
996                         var totS = Math.floor(totTime % 60);
997                         var strTotTime = 
998                                 (totH == 0 || isNaN(totH) ? '' : (widget._leadingZeros(totH) + ':'))
999                                 + widget._leadingZeros(totM) + ':' + widget._leadingZeros(totS);
1000                         
1001                         widget.setTimeText('' + strCrtTime + ' / ' + strTotTime);
1002                         
1003                         // Update time progress slider.
1004                         widget.vlc.refreshProgress();
1005                         
1006                         return widget;
1007                 },
1008                 
1009                 _state: function(code) {
1010                         var r;
1011                         $.each(widget.vlc.STATES, function(index, value) {
1012                                 if ('' + code == '' + value[0])
1013                                 {
1014                                         r = value;
1015                                         return false;
1016                                 }
1017                         });
1018                         
1019                         return r;
1020                 },
1021                 
1022                 refreshState: function() {
1023                         widget.$stateText
1024                                 .html(widget.vlc._state(widget.$video[0].input.state)[1]);
1025                                 
1026                         return widget;
1027                 },
1028
1029                 refreshVolume: function() {
1030                         var vol;
1031                         
1032                         if (widget.$video[0].audio.mute)
1033                                 vol = 0;
1034                         else
1035                                 vol = Math.floor(widget.$video[0].audio.volume);
1036                         
1037                         widget.setVolumeSlider(vol);
1038                         
1039                         return widget;
1040                 },
1041                 
1042                 refreshProgress: function() {
1043                         widget.setProgressSlider(widget.vlc.crtTime());
1044                         
1045                         return widget;
1046                 },
1047                 
1048                 /**
1049                 * Not supported for VLC.
1050                 */
1051                 refreshLoadedProgress: function() {
1052                         // TODO Currently not possible through VLC API.
1053                         
1054                         return widget;
1055                 },
1056
1057                 fullscreen: function() {
1058                         widget.$video[0].video.toggleFullscreen();
1059                 }
1060         }
1061 });
1062
1063 })( jQuery );