OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview MediaControls class implements media playback controls | 6 * @fileoverview MediaControls class implements media playback controls |
7 * that exist outside of the audio/video HTML element. | 7 * that exist outside of the audio/video HTML element. |
8 */ | 8 */ |
9 | 9 |
10 /** | 10 /** |
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 sliderContainer.classList.add('readonly'); | 377 sliderContainer.classList.add('readonly'); |
378 | 378 |
379 var valueToString = function(value) { | 379 var valueToString = function(value) { |
380 return MediaControls.formatTime_(this.media_.duration * value); | 380 return MediaControls.formatTime_(this.media_.duration * value); |
381 }.bind(this); | 381 }.bind(this); |
382 | 382 |
383 this.duration_.textContent = valueToString(1); | 383 this.duration_.textContent = valueToString(1); |
384 | 384 |
385 if (this.progressSlider_.setValueToStringFunction) | 385 if (this.progressSlider_.setValueToStringFunction) |
386 this.progressSlider_.setValueToStringFunction(valueToString); | 386 this.progressSlider_.setValueToStringFunction(valueToString); |
| 387 |
| 388 if (this.media_.seekable) |
| 389 this.restorePlayState(); |
387 }; | 390 }; |
388 | 391 |
389 /** | 392 /** |
390 * 'timeupdate' event handler. | 393 * 'timeupdate' event handler. |
391 * @private | 394 * @private |
392 */ | 395 */ |
393 MediaControls.prototype.onMediaProgress_ = function() { | 396 MediaControls.prototype.onMediaProgress_ = function() { |
394 if (!this.media_.duration) { | 397 if (!this.media_.duration) { |
395 this.displayProgress_(0, 1); | 398 this.displayProgress_(0, 1); |
396 return; | 399 return; |
(...skipping 13 matching lines...) Expand all Loading... |
410 this.onPlayStateChanged(); | 413 this.onPlayStateChanged(); |
411 }; | 414 }; |
412 | 415 |
413 /** | 416 /** |
414 * Called when the media playback is complete. | 417 * Called when the media playback is complete. |
415 */ | 418 */ |
416 MediaControls.prototype.onMediaComplete = function() {}; | 419 MediaControls.prototype.onMediaComplete = function() {}; |
417 | 420 |
418 /** | 421 /** |
419 * Called when play/pause state is changed or on playback progress. | 422 * Called when play/pause state is changed or on playback progress. |
| 423 * This is the right moment to save the play state. |
420 */ | 424 */ |
421 MediaControls.prototype.onPlayStateChanged = function() {}; | 425 MediaControls.prototype.onPlayStateChanged = function() {}; |
422 | 426 |
423 /** | 427 /** |
| 428 * Restore play state. Base implementation is empty. |
| 429 */ |
| 430 MediaControls.prototype.restorePlayState = function() {}; |
| 431 |
| 432 /** |
| 433 * Encode current play/pause status and the current time into the page URL. |
| 434 */ |
| 435 MediaControls.prototype.encodeStateIntoLocation = function() { |
| 436 if (!this.media_.duration) |
| 437 return; |
| 438 |
| 439 var playState = JSON.stringify({ |
| 440 play: this.isPlaying(), |
| 441 time: this.media_.currentTime |
| 442 }); |
| 443 |
| 444 var newLocation = document.location.origin + document.location.pathname + |
| 445 document.location.search + '#' + playState; |
| 446 |
| 447 history.replaceState(undefined, playState, newLocation); |
| 448 }; |
| 449 |
| 450 /** |
| 451 * Decode current play/pause status and the current time from the page URL. |
| 452 * @return {boolean} True if decode succeeded. |
| 453 */ |
| 454 MediaControls.prototype.decodeStateFromLocation = function() { |
| 455 var hash = document.location.hash.substring(1); |
| 456 if (hash) { |
| 457 try { |
| 458 var playState = JSON.parse(hash); |
| 459 if (!('time' in playState)) |
| 460 return false; |
| 461 |
| 462 this.media_.currentTime = playState.time; |
| 463 |
| 464 if (playState.play) |
| 465 this.play(); |
| 466 else |
| 467 this.pause(); |
| 468 |
| 469 return true; |
| 470 } catch (e) { |
| 471 console.warn('Cannot decode play state'); |
| 472 } |
| 473 } |
| 474 return false; |
| 475 }; |
| 476 |
| 477 /** |
424 * Create a customized slider control. | 478 * Create a customized slider control. |
425 * | 479 * |
426 * @param {HTMLElement} container The containing div element. | 480 * @param {HTMLElement} container The containing div element. |
427 * @param {number} value Initial value [0..1]. | 481 * @param {number} value Initial value [0..1]. |
428 * @param {number} range Number of distinct slider positions to be supported. | 482 * @param {number} range Number of distinct slider positions to be supported. |
429 * @param {function(number)} onChange Value change handler. | 483 * @param {function(number)} onChange Value change handler. |
430 * @param {function(boolean)} onDrag Drag begin/end handler. | 484 * @param {function(boolean)} onDrag Drag begin/end handler. |
431 * @constructor | 485 * @constructor |
432 */ | 486 */ |
433 | 487 |
(...skipping 499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
933 self.stateIcon_.setAttribute('visible', true); | 987 self.stateIcon_.setAttribute('visible', true); |
934 delay(function() { | 988 delay(function() { |
935 self.stateIcon_.setAttribute( | 989 self.stateIcon_.setAttribute( |
936 'state', self.isPlaying() ? 'play' : 'pause'); | 990 'state', self.isPlaying() ? 'play' : 'pause'); |
937 delay(hideStatusIcon, 1000); /* Twice the animation duration. */ | 991 delay(hideStatusIcon, 1000); /* Twice the animation duration. */ |
938 }); | 992 }); |
939 }); | 993 }); |
940 }; | 994 }; |
941 | 995 |
942 /** | 996 /** |
943 * 'durationchange' handler. | |
944 * @private | |
945 */ | |
946 VideoControls.prototype.onMediaDuration_ = function() { | |
947 MediaControls.prototype.onMediaDuration_.apply(this, arguments); | |
948 if (this.media_.duration && this.media_.seekable) | |
949 this.resumePosition(); | |
950 }; | |
951 | |
952 /** | |
953 * Toggle play/pause state. | 997 * Toggle play/pause state. |
954 */ | 998 */ |
955 VideoControls.prototype.togglePlayState = function() { | 999 VideoControls.prototype.togglePlayState = function() { |
956 if (this.isPlaying()) { | 1000 if (this.isPlaying()) { |
957 // User gave the Pause command. | 1001 // User gave the Pause command. |
958 this.savePosition(); | 1002 this.savePosition(); |
959 } | 1003 } |
960 MediaControls.prototype.togglePlayState.apply(this, arguments); | 1004 MediaControls.prototype.togglePlayState.apply(this, arguments); |
961 }; | 1005 }; |
962 | 1006 |
(...skipping 13 matching lines...) Expand all Loading... |
976 this.resumePositions_.removeValue(this.media_.src); | 1020 this.resumePositions_.removeValue(this.media_.src); |
977 } else { | 1021 } else { |
978 this.resumePositions_.setValue(this.media_.src, Math.floor(Math.max(0, | 1022 this.resumePositions_.setValue(this.media_.src, Math.floor(Math.max(0, |
979 this.media_.currentTime - VideoControls.RESUME_REWIND))); | 1023 this.media_.currentTime - VideoControls.RESUME_REWIND))); |
980 } | 1024 } |
981 }; | 1025 }; |
982 | 1026 |
983 /** | 1027 /** |
984 * Resume the playback position saved in the persistent storage. | 1028 * Resume the playback position saved in the persistent storage. |
985 */ | 1029 */ |
986 VideoControls.prototype.resumePosition = function() { | 1030 VideoControls.prototype.restorePlayState = function() { |
987 if (this.media_.duration >= VideoControls.RESUME_THRESHOLD) { | 1031 if (this.media_.duration >= VideoControls.RESUME_THRESHOLD) { |
988 var position = this.resumePositions_.getValue(this.media_.src); | 1032 var position = this.resumePositions_.getValue(this.media_.src); |
989 if (position) | 1033 if (position) |
990 this.media_.currentTime = position; | 1034 this.media_.currentTime = position; |
991 } | 1035 } |
992 }; | 1036 }; |
993 | 1037 |
994 /** | 1038 /** |
995 * Update style to best fit the size of the container. | 1039 * Update style to best fit the size of the container. |
996 */ | 1040 */ |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1174 AudioControls.prototype.onAdvanceClick_ = function(forward) { | 1218 AudioControls.prototype.onAdvanceClick_ = function(forward) { |
1175 if (!forward && | 1219 if (!forward && |
1176 (this.getMedia().currentTime > AudioControls.TRACK_RESTART_THRESHOLD)) { | 1220 (this.getMedia().currentTime > AudioControls.TRACK_RESTART_THRESHOLD)) { |
1177 // We are far enough from the beginning of the current track. | 1221 // We are far enough from the beginning of the current track. |
1178 // Restart it instead of than skipping to the previous one. | 1222 // Restart it instead of than skipping to the previous one. |
1179 this.getMedia().currentTime = 0; | 1223 this.getMedia().currentTime = 0; |
1180 } else { | 1224 } else { |
1181 this.advanceTrack_(forward); | 1225 this.advanceTrack_(forward); |
1182 } | 1226 } |
1183 }; | 1227 }; |
OLD | NEW |