|
|
|
|
| 363 |
// If the first frame hasn't loaded, kick off a throbber fade-in. |
363 |
// If the first frame hasn't loaded, kick off a throbber fade-in. |
| 364 |
if (this.video.readyState >= this.video.HAVE_CURRENT_DATA) |
364 |
if (this.video.readyState >= this.video.HAVE_CURRENT_DATA) |
| 365 |
this.firstFrameShown = true; |
365 |
this.firstFrameShown = true; |
| 366 |
|
366 |
|
| 367 |
// We can't determine the exact buffering status, but do know if it's |
367 |
// We can't determine the exact buffering status, but do know if it's |
| 368 |
// fully loaded. (If it's still loading, it will fire a progress event |
368 |
// fully loaded. (If it's still loading, it will fire a progress event |
| 369 |
// and we'll figure out the exact state then.) |
369 |
// and we'll figure out the exact state then.) |
| 370 |
this.bufferBar.setAttribute("max", 100); |
370 |
this.bufferBar.setAttribute("max", 100); |
| 371 |
if (this.video.networkState == this.video.NETWORK_LOADED) |
371 |
if (this.video.readyState >= this.video.HAVE_METADATA) |
| 372 |
this.bufferBar.setAttribute("value", 100); |
372 |
this.showBuffered(); |
| 373 |
else |
373 |
else |
| 374 |
this.bufferBar.setAttribute("value", 0); |
374 |
this.bufferBar.setAttribute("value", 0); |
| 375 |
|
375 |
|
| 376 |
// Set the current status icon. |
376 |
// Set the current status icon. |
| 377 |
if (this.video.error) { |
377 |
if (this.video.error) { |
| 378 |
this.statusIcon.setAttribute("type", "error"); |
378 |
this.statusIcon.setAttribute("type", "error"); |
| 379 |
this.setupStatusFader(true); |
379 |
this.setupStatusFader(true); |
| 380 |
} else { |
380 |
} else { |
|
|
| 451 |
this.isAudioOnly = (this.video instanceof HTMLAudioElement); |
451 |
this.isAudioOnly = (this.video instanceof HTMLAudioElement); |
| 452 |
this.setPlayButtonState(true); |
452 |
this.setPlayButtonState(true); |
| 453 |
break; |
453 |
break; |
| 454 |
case "durationchange": |
454 |
case "durationchange": |
| 455 |
var duration = Math.round(this.video.duration * 1000); // in ms |
455 |
var duration = Math.round(this.video.duration * 1000); // in ms |
| 456 |
this.durationChange(duration); |
456 |
this.durationChange(duration); |
| 457 |
break; |
457 |
break; |
| 458 |
case "progress": |
458 |
case "progress": |
| 459 |
var loaded = aEvent.loaded; |
459 |
this.showBuffered(); |
| 460 |
var total = aEvent.total; |
|
|
| 461 |
this.log("+++ load, " + loaded + " of " + total); |
| 462 |
// When the source is streaming, the value of .total is -1. Set the |
| 463 |
// progress bar to the maximum, since it's not useful. |
| 464 |
if (total == -1) |
| 465 |
total = loaded; |
| 466 |
this.bufferBar.max = total; |
| 467 |
this.bufferBar.value = loaded; |
| 468 |
this.setupStatusFader(); |
460 |
this.setupStatusFader(); |
| 469 |
break; |
461 |
break; |
| 470 |
case "suspend": |
462 |
case "suspend": |
| 471 |
this.setupStatusFader(); |
463 |
this.setupStatusFader(); |
| 472 |
break; |
464 |
break; |
| 473 |
case "timeupdate": |
465 |
case "timeupdate": |
| 474 |
var currentTime = Math.round(this.video.currentTime * 1000); // in ms |
466 |
var currentTime = Math.round(this.video.currentTime * 1000); // in ms |
| 475 |
var duration = Math.round(this.video.duration * 1000); // in ms |
467 |
var duration = Math.round(this.video.duration * 1000); // in ms |
|
|
| 592 |
duration = this.maxCurrentTimeSeen; |
584 |
duration = this.maxCurrentTimeSeen; |
| 593 |
this.durationChange(duration); |
585 |
this.durationChange(duration); |
| 594 |
} |
586 |
} |
| 595 |
|
587 |
|
| 596 |
this.log("time update @ " + currentTime + "ms of " + duration + "ms"); |
588 |
this.log("time update @ " + currentTime + "ms of " + duration + "ms"); |
| 597 |
this.scrubber.value = currentTime; |
589 |
this.scrubber.value = currentTime; |
| 598 |
}, |
590 |
}, |
| 599 |
|
591 |
|
|
|
592 |
showBuffered : function() { |
| 593 |
var duration = Math.round(this.video.duration * 1000); |
| 594 |
if (isNaN(duration)) |
| 595 |
duration = this.maxCurrentTimeSeen; |
| 596 |
|
| 597 |
function bsearch(hs, n, cmp) { |
| 598 |
var length = hs.length; |
| 599 |
var l = 0; |
| 600 |
var h = length; |
| 601 |
while (h - l > 1) { |
| 602 |
var m = l + ((h - l) / 2); |
| 603 |
var r = cmp(hs, m, n); |
| 604 |
if (r == 0) { |
| 605 |
l = m; |
| 606 |
break; |
| 607 |
} else if (r > 0) { |
| 608 |
l = m + 1; |
| 609 |
} else { |
| 610 |
h = m; |
| 611 |
} |
| 612 |
} |
| 613 |
return l < length ? l : -1; |
| 614 |
} |
| 615 |
|
| 616 |
function bufferedCompare(buffered, i, time) { |
| 617 |
if (time > buffered.end(i)) { |
| 618 |
return 1; |
| 619 |
} else if (time >= buffered.start(i)) { |
| 620 |
return 0; |
| 621 |
} |
| 622 |
return -1; |
| 623 |
} |
| 624 |
|
| 625 |
// Find the range that the current play position is in and use that |
| 626 |
// range for bufferBar. At some point we may support multiple ranges |
| 627 |
// displayed in the bar. |
| 628 |
var currentTime = this.video.currentTime; |
| 629 |
var buffered = this.video.buffered; |
| 630 |
var index = bsearch(buffered, currentTime, bufferedCompare); |
| 631 |
var endTime = 0; |
| 632 |
if (index >= 0) { |
| 633 |
endTime = Math.round(buffered.end(index) * 1000); |
| 634 |
} |
| 635 |
this.bufferBar.max = duration; |
| 636 |
this.bufferBar.value = endTime; |
| 637 |
}, |
| 638 |
|
| 600 |
onVolumeMouseInOut : function (event) { |
639 |
onVolumeMouseInOut : function (event) { |
| 601 |
// Ignore events caused by transitions between mute button and volumeStack, |
640 |
// Ignore events caused by transitions between mute button and volumeStack, |
| 602 |
// or between nodes inside these two elements. |
641 |
// or between nodes inside these two elements. |
| 603 |
if (this.isEventWithin(event, this.muteButton, this.volumeStack)) |
642 |
if (this.isEventWithin(event, this.muteButton, this.volumeStack)) |
| 604 |
return; |
643 |
return; |
| 605 |
var isMouseOver = (event.type == "mouseover"); |
644 |
var isMouseOver = (event.type == "mouseover"); |
| 606 |
this.startFade(this.volumeStack, isMouseOver); |
645 |
this.startFade(this.volumeStack, isMouseOver); |
| 607 |
}, |
646 |
}, |