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

Side by Side 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: 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 'use strict'; 5 'use strict';
6 6
7 // Inverval for updating media info (in ms).
hirono 2014/07/24 02:12:36 nit: jsdoc @const, @type
yoshiki 2014/07/24 02:57:32 Done.
8 var MEDIA_UPDATE_INTERVAL = 250;
9
7 /** 10 /**
8 * This class is the dummy class which has same interface as VideoElement. This 11 * This class is the dummy class which has same interface as VideoElement. This
9 * behaves like VideoElement, and is used for making Chromecast player 12 * behaves like VideoElement, and is used for making Chromecast player
10 * controlled instead of the true Video Element tag. 13 * controlled instead of the true Video Element tag.
11 * 14 *
12 * @constructor 15 * @constructor
hirono 2014/07/24 02:12:36 nit: @param
yoshiki 2014/07/24 02:57:32 Done.
13 */ 16 */
14 function CastVideoElement() { 17 function CastVideoElement(mediaInfo, session) {
15 this.duration_ = null; 18 this.mediaInfo_ = mediaInfo;
19 this.castMedia_ = null;
20 this.castSession_ = session;
21 this.lastDuration_ = null;
16 this.currentTime_ = null; 22 this.currentTime_ = null;
17 this.src_ = ''; 23 this.src_ = '';
18 this.volume_ = 100; 24 this.volume_ = 100;
25 this.currentMediaPlayerState_ = null;
26 this.currentMediaCurrentTime_ = null;
27 this.currentMediaDuration_ = null;
28
29 this.onCastMediaUpdatedBound_ = this.onCastMediaUpdated_.bind(this);
19 } 30 }
20 31
21 CastVideoElement.prototype = { 32 CastVideoElement.prototype = {
22 __proto__: cr.EventTarget.prototype, 33 __proto__: cr.EventTarget.prototype,
23 34
24 /** 35 /**
25 * Returns a parent node. This must always be null. 36 * Returns a parent node. This must always be null.
26 * @return {Element} 37 * @return {Element}
27 */ 38 */
28 get parentNode() { 39 get parentNode() {
29 return null; 40 return null;
30 }, 41 },
31 42
32 /** 43 /**
33 * The total time of the video. 44 * The total time of the video.
hirono 2014/07/24 02:12:36 Comment about the unit of time is useful.
yoshiki 2014/07/24 02:57:32 Done.
34 * @type {number} 45 * @type {number}
hirono 2014/07/24 02:12:36 nit: @return Same for the followings.
yoshiki 2014/07/24 02:57:31 I think we don't need it because it's a getter met
hirono 2014/07/24 03:42:49 nit: So please just make #37 consistent with other
yoshiki 2014/07/24 05:19:00 Done.
35 */ 46 */
36 get duration() { 47 get duration() {
37 return this.duration_; 48 if (this.castMedia_ && this.castMedia_.media) {
49 this.lastDuration_ = this.castMedia_.media.duration;
hirono 2014/07/24 02:12:36 Changing a value in a getter is a bit strange. Can
yoshiki 2014/07/24 02:57:31 Done.
50 return this.castMedia_.media.duration;
51 }
52
53 return this.lastDuration_;
38 }, 54 },
39 55
40 /** 56 /**
41 * The current timestamp of the video. 57 * The current timestamp of the video.
42 * @type {number} 58 * @type {number}
hirono 2014/07/24 02:12:36 @return {?number} ?
yoshiki 2014/07/24 02:57:32 Done.
43 */ 59 */
44 get currentTime() { 60 get currentTime() {
45 return this.currentTime_; 61 return this.castMedia_ ? this.castMedia_.getEstimatedTime() : null;
46 }, 62 },
47 set currentTime(currentTime) { 63 set currentTime(currentTime) {
48 this.currentTime_ = currentTime; 64 // TODO(yoshiki): Support seek.
hirono 2014/07/24 02:12:36 How about adding throw new Error('Not implemented'
yoshiki 2014/07/24 02:57:32 Please leave it as it is, since this setter is cal
hirono 2014/07/24 03:42:49 SGTM.
49 }, 65 },
50 66
51 /** 67 /**
52 * If this video is pauses or not. 68 * If this video is pauses or not.
53 * @type {boolean} 69 * @type {boolean}
54 */ 70 */
55 get paused() { 71 get paused() {
56 return false; 72 if (!this.castMedia_)
73 return false;
74
75 return this.castMedia_.playerState == chrome.cast.media.PlayerState.PAUSED;
hirono 2014/07/24 02:12:36 === ? Same for others.
yoshiki 2014/07/24 02:57:31 Done.
57 }, 76 },
58 77
59 /** 78 /**
60 * If this video is ended or not. 79 * If this video is ended or not.
61 * @type {boolean} 80 * @type {boolean}
62 */ 81 */
63 get ended() { 82 get ended() {
64 return false; 83 if (!this.castMedia_)
84 return true;
85
86 return this.castMedia_.idleReason == chrome.cast.media.IdleReason.FINISHED;
65 }, 87 },
66 88
67 /** 89 /**
68 * If this video is seelable or not. 90 * If this video is seelable or not.
69 * @type {boolean} 91 * @type {boolean}
70 */ 92 */
71 get seekable() { 93 get seekable() {
94 // TODO(yoshiki): Support seek.
72 return false; 95 return false;
73 }, 96 },
74 97
75 /** 98 /**
76 * Value of the volume 99 * Value of the volume
77 * @type {number} 100 * @type {number}
78 */ 101 */
79 get volume() { 102 get volume() {
80 return this.volume_; 103 return this.castSession_.receiver.volume.muted ?
104 0 :
105 this.castSession_.receiver.volume.level;
81 }, 106 },
82 set volume(volume) { 107 set volume(volume) {
83 this.volume_ = volume; 108 var VOLUME_EPS = 0.01; // Threshold for ignoring a small change.
109
110 // Ignores < 1% change.
111 if (Math.abs(this.castSession_.receiver.volume.level - volume) < VOLUME_EPS)
112 return;
113
114 if (this.castSession_.receiver.volume.muted) {
115 if (volume < VOLUME_EPS)
116 return;
117
118 // Unmute before setting volume.
119 this.castSession_.setReceiverMuted(false,
120 function() {},
121 this.onCastCommandError_.wrap(this));
122
123 this.castSession_.setReceiverVolumeLevel(volume,
124 function() {},
125 this.onCastCommandError_.wrap(this));
126 } else {
127 if (volume < VOLUME_EPS) {
128 this.castSession_.setReceiverMuted(true,
129 function() {},
130 this.onCastCommandError_.wrap(this));
131 return;
132 }
133
134 this.castSession_.setReceiverVolumeLevel(volume,
135 function() {},
136 this.onCastCommandError_.wrap(this));
137 }
84 }, 138 },
85 139
86 /** 140 /**
87 * Returns the source of the current video. 141 * Returns the source of the current video.
88 * @return {string} 142 * @return {null}
hirono 2014/07/24 02:12:36 Maybe string is OK because it's nullable.
yoshiki 2014/07/24 02:57:32 changed to '?string'
hirono 2014/07/24 03:42:49 Yes, I misunderstood.
89 */ 143 */
90 get src() { 144 get src() {
91 return this.src_; 145 return null;
92 }, 146 },
93 147
94 /** 148 /**
95 * Plays the video. 149 * Plays the video.
96 */ 150 */
97 play: function() { 151 play: function() {
98 // TODO(yoshiki): Implement this. 152 if (!this.castMedia_) {
153 this.load(function() {
154 this.castMedia_.play(null,
155 function () {},
156 this.onCastCommandError_.wrap(this));
157 }.wrap(this));
158 return;
159 }
160
161 this.castMedia_.play(null,
162 function () {},
163 this.onCastCommandError_.wrap(this));
99 }, 164 },
100 165
101 /** 166 /**
102 * Pauses the video. 167 * Pauses the video.
103 */ 168 */
104 pause: function() { 169 pause: function() {
105 // TODO(yoshiki): Implement this. 170 if (!this.castMedia_)
171 return;
172
173 this.castMedia_.pause(null,
174 function () {},
175 this.onCastCommandError_.wrap(this));
106 }, 176 },
107 177
108 /** 178 /**
109 * Loads the video. 179 * Loads the video.
110 */ 180 */
111 load: function() { 181 load: function(opt_callback) {
112 // TODO(yoshiki): Implement this. 182 var request = new chrome.cast.media.LoadRequest(this.mediaInfo_);
183 this.castSession_.loadMedia(request,
184 function(media) {
185 this.onMediaDiscovered_(media);
186 if (opt_callback)
187 opt_callback();
188 }.bind(this),
189 this.onCastCommandError_.wrap(this));
190 },
191
192 /**
193 * Unloads the video.
194 * @private
195 */
196 unloadMedia_: function() {
197 this.castMedia_.removeUpdateListener(this.onCastMediaUpdatedBound_);
198 this.castMedia_ = null;
199 clearInterval(this.updateTimerId_);
200 },
201
202 /**
203 * This method is called periodically to update media information while the
204 * media is loaded.
205 * @private
206 */
207 onPeriodicalUpdateTimer_: function() {
208 if (!this.castMedia_)
209 return;
210
211 if (this.castMedia_.playerState == chrome.cast.media.PlayerState.PLAYING)
212 this.onCastMediaUpdated_(true);
213 },
214
215 /**
216 * This method should be called when a media file is loaded.
217 * @param {chrome.cast.Media} media Media object which was discovered.
218 * @private
219 */
220 onMediaDiscovered_: function(media) {
221 this.castMedia_ = media;
hirono 2014/07/24 02:12:36 Should we check this.castMedia_ == null since it m
yoshiki 2014/07/24 02:57:32 Done.
222 this.onCastMediaUpdated_(true);
223 media.addUpdateListener(this.onCastMediaUpdatedBound_);
224 this.updateTimerId_ = setInterval(this.onPeriodicalUpdateTimer_.bind(this),
225 MEDIA_UPDATE_INTERVAL);
226 },
227
228 /**
229 * This method should be called when a media command to cast is failed.
230 * @private
231 */
232 onCastCommandError_: function() {
233 this.unloadMedia_();
234 this.dispatchEvent(new Event('error'));
235 },
236
237 /**
238 * This is called when any media data is updated and by the periodical timer
239 * is fired.
240 *
241 * @param {boolean} alive Media availability. False if it's unavailable.
242 * @private
243 */
244 onCastMediaUpdated_: function(alive) {
245 if (!this.castMedia_)
246 return;
247
248 var media = this.castMedia_;
249 if (this.currentMediaPlayerState_ != media.playerState) {
250 var oldPlayState = false;
251 var oldState = this.currentMediaPlayerState_;
252 if (oldState == chrome.cast.media.PlayerState.BUFFERING ||
253 oldState == chrome.cast.media.PlayerState.PLAYING) {
254 oldPlayState = true;
255 }
256 var newPlayState = false;
257 var newState = media.playerState;
258 if (newState == chrome.cast.media.PlayerState.BUFFERING ||
259 newState == chrome.cast.media.PlayerState.PLAYING) {
260 newPlayState = true;
261 }
262 if (!oldPlayState && newPlayState)
263 this.dispatchEvent(new Event('play'));
264 if (oldPlayState && !newPlayState)
265 this.dispatchEvent(new Event('pause'));
266
267 this.currentMediaPlayerState_ = newState;
268 }
269 if (this.currentMediaCurrentTime_ != media.getEstimatedTime()) {
270 this.dispatchEvent(new Event('timeupdate'));
271 this.currentMediaCurrentTime_ = media.getEstimatedTime();
272 }
273
274 if (this.currentMediaDuration_ != media.media.duration) {
275 this.dispatchEvent(new Event('durationchange'));
276 this.currentMediaDuration_ = media.media.duration;
277 }
278
279 // Media is being unloaded.
280 if (!alive) {
281 this.unloadMedia_();
282 return;
283 }
113 }, 284 },
114 }; 285 };
OLDNEW
« no previous file with comments | « no previous file | ui/file_manager/video_player/js/cast/caster.js » ('j') | ui/file_manager/video_player/js/video_player.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698