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

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

Powered by Google App Engine
This is Rietveld 408576698