Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(798)

Unified Diff: ui/file_manager/video_player/js/cast/cast_video_element.js

Issue 412813002: Video Player: Support casting a video (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: addressed the comments Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/file_manager/video_player/js/cast/cast_video_element.js
diff --git a/ui/file_manager/video_player/js/cast/cast_video_element.js b/ui/file_manager/video_player/js/cast/cast_video_element.js
index 299fa2bb5d3f1c3740861a3e1ff6379eae9091b6..9fe9d9c7de51c30b0f2d501d8418fb3e77c7452b 100644
--- a/ui/file_manager/video_player/js/cast/cast_video_element.js
+++ b/ui/file_manager/video_player/js/cast/cast_video_element.js
@@ -5,17 +5,34 @@
'use strict';
/**
+ * Inverval for updating media info (in ms).
+ * @type {number}
+ * @const
+ */
+var MEDIA_UPDATE_INTERVAL = 250;
+
+/**
* This class is the dummy class which has same interface as VideoElement. This
* behaves like VideoElement, and is used for making Chromecast player
* controlled instead of the true Video Element tag.
*
+ * @param {chrome.cast.media.MediaInfo} mediaInfo Data of the media to play.
+ * @param {chrome.cast.Session} session Session to play a video on.
* @constructor
*/
-function CastVideoElement() {
- this.duration_ = null;
+function CastVideoElement(mediaInfo, session) {
+ this.mediaInfo_ = mediaInfo;
+ this.castMedia_ = null;
+ this.castSession_ = session;
this.currentTime_ = null;
this.src_ = '';
this.volume_ = 100;
+ this.currentMediaPlayerState_ = null;
+ this.currentMediaCurrentTime_ = null;
+ this.currentMediaDuration_ = null;
+ this.pausing_ = false;
+
+ this.onCastMediaUpdatedBound_ = this.onCastMediaUpdated_.bind(this);
}
CastVideoElement.prototype = {
@@ -30,22 +47,22 @@ CastVideoElement.prototype = {
},
/**
- * The total time of the video.
- * @type {number}
+ * The total time of the video (in sec).
+ * @type {?number}
*/
get duration() {
- return this.duration_;
+ return this.currentMediaDuration_;
},
/**
- * The current timestamp of the video.
- * @type {number}
+ * The current timestamp of the video (in sec).
+ * @type {?number}
*/
get currentTime() {
- return this.currentTime_;
+ return this.castMedia_ ? this.castMedia_.getEstimatedTime() : null;
},
set currentTime(currentTime) {
- this.currentTime_ = currentTime;
+ // TODO(yoshiki): Support seek.
},
/**
@@ -53,7 +70,11 @@ CastVideoElement.prototype = {
* @type {boolean}
*/
get paused() {
- return false;
+ if (!this.castMedia_)
+ return false;
+
+ return this.pausing_ ||
+ this.castMedia_.playerState === chrome.cast.media.PlayerState.PAUSED;
},
/**
@@ -61,7 +82,10 @@ CastVideoElement.prototype = {
* @type {boolean}
*/
get ended() {
- return false;
+ if (!this.castMedia_)
+ return true;
+
+ return this.castMedia_.idleReason === chrome.cast.media.IdleReason.FINISHED;
},
/**
@@ -69,6 +93,7 @@ CastVideoElement.prototype = {
* @type {boolean}
*/
get seekable() {
+ // TODO(yoshiki): Support seek.
return false;
},
@@ -77,38 +102,197 @@ CastVideoElement.prototype = {
* @type {number}
*/
get volume() {
- return this.volume_;
+ return this.castSession_.receiver.volume.muted ?
+ 0 :
+ this.castSession_.receiver.volume.level;
},
set volume(volume) {
- this.volume_ = volume;
+ var VOLUME_EPS = 0.01; // Threshold for ignoring a small change.
+
+ // Ignores < 1% change.
+ if (Math.abs(this.castSession_.receiver.volume.level - volume) < VOLUME_EPS)
+ return;
+
+ if (this.castSession_.receiver.volume.muted) {
+ if (volume < VOLUME_EPS)
+ return;
+
+ // Unmute before setting volume.
+ this.castSession_.setReceiverMuted(false,
+ function() {},
+ this.onCastCommandError_.wrap(this));
+
+ this.castSession_.setReceiverVolumeLevel(volume,
+ function() {},
+ this.onCastCommandError_.wrap(this));
+ } else {
+ if (volume < VOLUME_EPS) {
+ this.castSession_.setReceiverMuted(true,
+ function() {},
+ this.onCastCommandError_.wrap(this));
+ return;
+ }
+
+ this.castSession_.setReceiverVolumeLevel(volume,
+ function() {},
+ this.onCastCommandError_.wrap(this));
+ }
},
/**
* Returns the source of the current video.
- * @return {string}
+ * @return {?string}
*/
get src() {
- return this.src_;
+ return null;
},
/**
* Plays the video.
*/
play: function() {
- // TODO(yoshiki): Implement this.
+ if (!this.castMedia_) {
+ this.load(function() {
+ this.castMedia_.play(null,
+ function () {},
+ this.onCastCommandError_.wrap(this));
+ }.wrap(this));
+ return;
+ }
+
+ this.castMedia_.play(null,
+ function () {},
+ this.onCastCommandError_.wrap(this));
},
/**
* Pauses the video.
*/
pause: function() {
- // TODO(yoshiki): Implement this.
+ if (!this.castMedia_)
+ return;
+
+ this.pausing_ = true;
+ this.castMedia_.pause(null,
+ function () {
+ this.pausing_ = false;
+ }.wrap(this),
+ function () {
+ this.pausing_ = false;
+ this.onCastCommandError_();
+ }.wrap(this));
},
/**
* Loads the video.
*/
- load: function() {
- // TODO(yoshiki): Implement this.
+ load: function(opt_callback) {
+ var request = new chrome.cast.media.LoadRequest(this.mediaInfo_);
+ this.castSession_.loadMedia(request,
+ function(media) {
+ this.onMediaDiscovered_(media);
+ if (opt_callback)
+ opt_callback();
+ }.bind(this),
+ this.onCastCommandError_.wrap(this));
+ },
+
+ /**
+ * Unloads the video.
+ * @private
+ */
+ unloadMedia_: function() {
+ this.castMedia_.removeUpdateListener(this.onCastMediaUpdatedBound_);
+ this.castMedia_ = null;
+ clearInterval(this.updateTimerId_);
+ },
+
+ /**
+ * This method is called periodically to update media information while the
+ * media is loaded.
+ * @private
+ */
+ onPeriodicalUpdateTimer_: function() {
+ if (!this.castMedia_)
+ return;
+
+ if (this.castMedia_.playerState === chrome.cast.media.PlayerState.PLAYING)
+ this.onCastMediaUpdated_(true);
+ },
+
+ /**
+ * This method should be called when a media file is loaded.
+ * @param {chrome.cast.Media} media Media object which was discovered.
+ * @private
+ */
+ onMediaDiscovered_: function(media) {
+ if (this.castMedia_ !== null) {
+ this.unloadMedia_();
+ console.info('New media is found and the old media is overridden.');
+ }
+
+ this.castMedia_ = media;
+ this.onCastMediaUpdated_(true);
+ media.addUpdateListener(this.onCastMediaUpdatedBound_);
+ this.updateTimerId_ = setInterval(this.onPeriodicalUpdateTimer_.bind(this),
+ MEDIA_UPDATE_INTERVAL);
+ },
+
+ /**
+ * This method should be called when a media command to cast is failed.
+ * @private
+ */
+ onCastCommandError_: function() {
+ this.unloadMedia_();
+ this.dispatchEvent(new Event('error'));
+ },
+
+ /**
+ * This is called when any media data is updated and by the periodical timer
+ * is fired.
+ *
+ * @param {boolean} alive Media availability. False if it's unavailable.
+ * @private
+ */
+ onCastMediaUpdated_: function(alive) {
+ if (!this.castMedia_)
+ return;
+
+ var media = this.castMedia_;
+ if (this.currentMediaPlayerState_ !== media.playerState) {
+ var oldPlayState = false;
+ var oldState = this.currentMediaPlayerState_;
+ if (oldState === chrome.cast.media.PlayerState.BUFFERING ||
+ oldState === chrome.cast.media.PlayerState.PLAYING) {
+ oldPlayState = true;
+ }
+ var newPlayState = false;
+ var newState = media.playerState;
+ if (newState === chrome.cast.media.PlayerState.BUFFERING ||
+ newState === chrome.cast.media.PlayerState.PLAYING) {
+ newPlayState = true;
+ }
+ if (!oldPlayState && newPlayState)
+ this.dispatchEvent(new Event('play'));
+ if (oldPlayState && !newPlayState)
+ this.dispatchEvent(new Event('pause'));
+
+ this.currentMediaPlayerState_ = newState;
+ }
+ if (this.currentMediaCurrentTime_ !== media.getEstimatedTime()) {
+ this.dispatchEvent(new Event('timeupdate'));
+ this.currentMediaCurrentTime_ = media.getEstimatedTime();
+ }
+
+ if (this.currentMediaDuration_ !== media.media.duration) {
+ this.dispatchEvent(new Event('durationchange'));
+ this.currentMediaDuration_ = media.media.duration;
+ }
+
+ // Media is being unloaded.
+ if (!alive) {
+ this.unloadMedia_();
+ return;
+ }
},
};
« no previous file with comments | « no previous file | ui/file_manager/video_player/js/video_player.js » ('j') | ui/file_manager/video_player/js/video_player.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698