OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2011 Apple Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions | |
6 * are met: | |
7 * 1. Redistributions of source code must retain the above copyright | |
8 * notice, this list of conditions and the following disclaimer. | |
9 * 2. Redistributions in binary form must reproduce the above copyright | |
10 * notice, this list of conditions and the following disclaimer in the | |
11 * documentation and/or other materials provided with the distribution. | |
12 * | |
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | |
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | |
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 */ | |
25 | |
26 #include "config.h" | |
27 #include "core/html/MediaController.h" | |
28 | |
29 #include "bindings/core/v8/ExceptionMessages.h" | |
30 #include "bindings/core/v8/ExceptionState.h" | |
31 #include "bindings/core/v8/ExceptionStatePlaceholder.h" | |
32 #include "core/dom/ExceptionCode.h" | |
33 #include "core/dom/ExecutionContext.h" | |
34 #include "core/events/Event.h" | |
35 #include "core/events/GenericEventQueue.h" | |
36 #include "core/html/HTMLMediaElement.h" | |
37 #include "core/html/TimeRanges.h" | |
38 #include "platform/Clock.h" | |
39 #include "wtf/CurrentTime.h" | |
40 #include "wtf/StdLibExtras.h" | |
41 #include "wtf/text/AtomicString.h" | |
42 | |
43 namespace blink { | |
44 | |
45 PassRefPtrWillBeRawPtr<MediaController> MediaController::create(ExecutionContext
* context) | |
46 { | |
47 return adoptRefWillBeNoop(new MediaController(context)); | |
48 } | |
49 | |
50 MediaController::MediaController(ExecutionContext* context) | |
51 : m_paused(false) | |
52 , m_defaultPlaybackRate(1) | |
53 , m_volume(1) | |
54 , m_position(MediaPlayer::invalidTime()) | |
55 , m_muted(false) | |
56 , m_readyState(HTMLMediaElement::HAVE_NOTHING) | |
57 , m_playbackState(WAITING) | |
58 , m_pendingEventsQueue(GenericEventQueue::create(this)) | |
59 , m_clearPositionTimer(this, &MediaController::clearPositionTimerFired) | |
60 , m_clock(Clock::create()) | |
61 , m_executionContext(context) | |
62 , m_timeupdateTimer(this, &MediaController::timeupdateTimerFired) | |
63 , m_previousTimeupdateTime(0) | |
64 { | |
65 ScriptWrappable::init(this); | |
66 } | |
67 | |
68 MediaController::~MediaController() | |
69 { | |
70 } | |
71 | |
72 void MediaController::addMediaElement(HTMLMediaElement* element) | |
73 { | |
74 ASSERT(element); | |
75 ASSERT(!m_mediaElements.contains(element)); | |
76 | |
77 m_mediaElements.add(element); | |
78 bringElementUpToSpeed(element); | |
79 } | |
80 | |
81 void MediaController::removeMediaElement(HTMLMediaElement* element) | |
82 { | |
83 ASSERT(element); | |
84 ASSERT(m_mediaElements.contains(element)); | |
85 m_mediaElements.remove(m_mediaElements.find(element)); | |
86 } | |
87 | |
88 PassRefPtrWillBeRawPtr<TimeRanges> MediaController::buffered() const | |
89 { | |
90 if (m_mediaElements.isEmpty()) | |
91 return TimeRanges::create(); | |
92 | |
93 // The buffered attribute must return a new static normalized TimeRanges obj
ect that represents | |
94 // the intersection of the ranges of the media resources of the slaved media
elements that the | |
95 // user agent has buffered, at the time the attribute is evaluated. | |
96 MediaElementSequence::const_iterator it = m_mediaElements.begin(); | |
97 RefPtrWillBeRawPtr<TimeRanges> bufferedRanges = (*it)->buffered(); | |
98 for (++it; it != m_mediaElements.end(); ++it) | |
99 bufferedRanges->intersectWith((*it)->buffered().get()); | |
100 return bufferedRanges; | |
101 } | |
102 | |
103 PassRefPtrWillBeRawPtr<TimeRanges> MediaController::seekable() const | |
104 { | |
105 if (m_mediaElements.isEmpty()) | |
106 return TimeRanges::create(); | |
107 | |
108 // The seekable attribute must return a new static normalized TimeRanges obj
ect that represents | |
109 // the intersection of the ranges of the media resources of the slaved media
elements that the | |
110 // user agent is able to seek to, at the time the attribute is evaluated. | |
111 MediaElementSequence::const_iterator it = m_mediaElements.begin(); | |
112 RefPtrWillBeRawPtr<TimeRanges> seekableRanges = (*it)->seekable(); | |
113 for (++it; it != m_mediaElements.end(); ++it) | |
114 seekableRanges->intersectWith((*it)->seekable().get()); | |
115 return seekableRanges; | |
116 } | |
117 | |
118 PassRefPtrWillBeRawPtr<TimeRanges> MediaController::played() | |
119 { | |
120 if (m_mediaElements.isEmpty()) | |
121 return TimeRanges::create(); | |
122 | |
123 // The played attribute must return a new static normalized TimeRanges objec
t that represents | |
124 // the union of the ranges of the media resources of the slaved media elemen
ts that the | |
125 // user agent has so far rendered, at the time the attribute is evaluated. | |
126 MediaElementSequence::const_iterator it = m_mediaElements.begin(); | |
127 RefPtrWillBeRawPtr<TimeRanges> playedRanges = (*it)->played(); | |
128 for (++it; it != m_mediaElements.end(); ++it) | |
129 playedRanges->unionWith((*it)->played().get()); | |
130 return playedRanges; | |
131 } | |
132 | |
133 double MediaController::duration() const | |
134 { | |
135 // FIXME: Investigate caching the maximum duration and only updating the cac
hed value | |
136 // when the slaved media elements' durations change. | |
137 double maxDuration = 0; | |
138 for (MediaElementSequence::const_iterator it = m_mediaElements.begin(); it !
= m_mediaElements.end(); ++it) { | |
139 double duration = (*it)->duration(); | |
140 if (std::isnan(duration)) | |
141 continue; | |
142 maxDuration = std::max(maxDuration, duration); | |
143 } | |
144 return maxDuration; | |
145 } | |
146 | |
147 double MediaController::currentTime() const | |
148 { | |
149 if (m_mediaElements.isEmpty()) | |
150 return 0; | |
151 | |
152 if (m_position == MediaPlayer::invalidTime()) { | |
153 // Some clocks may return times outside the range of [0..duration]. | |
154 m_position = std::max(0.0, std::min(duration(), m_clock->currentTime()))
; | |
155 m_clearPositionTimer.startOneShot(0, FROM_HERE); | |
156 } | |
157 | |
158 return m_position; | |
159 } | |
160 | |
161 void MediaController::setCurrentTime(double time, ExceptionState& exceptionState
) | |
162 { | |
163 // When the user agent is to seek the media controller to a particular new p
layback position, | |
164 // it must follow these steps: | |
165 // If the new playback position is less than zero, then set it to zero. | |
166 time = std::max(0.0, time); | |
167 | |
168 // If the new playback position is greater than the media controller duratio
n, then set it | |
169 // to the media controller duration. | |
170 time = std::min(time, duration()); | |
171 | |
172 // Set the media controller position to the new playback position. | |
173 m_position = time; | |
174 m_clock->setCurrentTime(time); | |
175 | |
176 // Seek each slaved media element to the new playback position relative to t
he media element timeline. | |
177 for (MediaElementSequence::const_iterator it = m_mediaElements.begin(); it !
= m_mediaElements.end(); ++it) | |
178 (*it)->seek(time, exceptionState); | |
179 | |
180 scheduleTimeupdateEvent(); | |
181 } | |
182 | |
183 void MediaController::unpause() | |
184 { | |
185 // When the unpause() method is invoked, if the MediaController is a paused
media controller, | |
186 if (!m_paused) | |
187 return; | |
188 | |
189 // the user agent must change the MediaController into a playing media contr
oller, | |
190 m_paused = false; | |
191 // queue a task to fire a simple event named play at the MediaController, | |
192 scheduleEvent(EventTypeNames::play); | |
193 // and then report the controller state of the MediaController. | |
194 reportControllerState(); | |
195 } | |
196 | |
197 void MediaController::play() | |
198 { | |
199 // When the play() method is invoked, the user agent must invoke the play me
thod of each | |
200 // slaved media element in turn, | |
201 for (MediaElementSequence::const_iterator it = m_mediaElements.begin(); it !
= m_mediaElements.end(); ++it) | |
202 (*it)->play(); | |
203 | |
204 // and then invoke the unpause method of the MediaController. | |
205 unpause(); | |
206 } | |
207 | |
208 void MediaController::pause() | |
209 { | |
210 // When the pause() method is invoked, if the MediaController is a playing m
edia controller, | |
211 if (m_paused) | |
212 return; | |
213 | |
214 // then the user agent must change the MediaController into a paused media c
ontroller, | |
215 m_paused = true; | |
216 // queue a task to fire a simple event named pause at the MediaController, | |
217 scheduleEvent(EventTypeNames::pause); | |
218 // and then report the controller state of the MediaController. | |
219 reportControllerState(); | |
220 } | |
221 | |
222 void MediaController::setDefaultPlaybackRate(double rate) | |
223 { | |
224 if (m_defaultPlaybackRate == rate) | |
225 return; | |
226 | |
227 // The defaultPlaybackRate attribute, on setting, must set the MediaControll
er's media controller | |
228 // default playback rate to the new value, | |
229 m_defaultPlaybackRate = rate; | |
230 | |
231 // then queue a task to fire a simple event named ratechange at the MediaCon
troller. | |
232 scheduleEvent(EventTypeNames::ratechange); | |
233 } | |
234 | |
235 double MediaController::playbackRate() const | |
236 { | |
237 return m_clock->playRate(); | |
238 } | |
239 | |
240 void MediaController::setPlaybackRate(double rate) | |
241 { | |
242 if (m_clock->playRate() == rate) | |
243 return; | |
244 | |
245 // The playbackRate attribute, on setting, must set the MediaController's me
dia controller | |
246 // playback rate to the new value, | |
247 m_clock->setPlayRate(rate); | |
248 | |
249 for (MediaElementSequence::const_iterator it = m_mediaElements.begin(); it !
= m_mediaElements.end(); ++it) | |
250 (*it)->updatePlaybackRate(); | |
251 | |
252 // then queue a task to fire a simple event named ratechange at the MediaCon
troller. | |
253 scheduleEvent(EventTypeNames::ratechange); | |
254 } | |
255 | |
256 void MediaController::setVolume(double level, ExceptionState& exceptionState) | |
257 { | |
258 if (m_volume == level) | |
259 return; | |
260 | |
261 // If the new value is outside the range 0.0 to 1.0 inclusive, then, on sett
ing, an | |
262 // IndexSizeError exception must be raised instead. | |
263 if (level < 0 || level > 1) { | |
264 exceptionState.throwDOMException(IndexSizeError, ExceptionMessages::inde
xOutsideRange("volume", level, 0.0, ExceptionMessages::InclusiveBound, 1.0, Exce
ptionMessages::InclusiveBound)); | |
265 return; | |
266 } | |
267 | |
268 // The volume attribute, on setting, if the new value is in the range 0.0 to
1.0 inclusive, | |
269 // must set the MediaController's media controller volume multiplier to the
new value | |
270 m_volume = level; | |
271 | |
272 // and queue a task to fire a simple event named volumechange at the MediaCo
ntroller. | |
273 scheduleEvent(EventTypeNames::volumechange); | |
274 | |
275 for (MediaElementSequence::const_iterator it = m_mediaElements.begin(); it !
= m_mediaElements.end(); ++it) | |
276 (*it)->updateVolume(); | |
277 } | |
278 | |
279 void MediaController::setMuted(bool flag) | |
280 { | |
281 if (m_muted == flag) | |
282 return; | |
283 | |
284 // The muted attribute, on setting, must set the MediaController's media con
troller mute override | |
285 // to the new value | |
286 m_muted = flag; | |
287 | |
288 // and queue a task to fire a simple event named volumechange at the MediaCo
ntroller. | |
289 scheduleEvent(EventTypeNames::volumechange); | |
290 | |
291 for (MediaElementSequence::const_iterator it = m_mediaElements.begin(); it !
= m_mediaElements.end(); ++it) | |
292 (*it)->updateVolume(); | |
293 } | |
294 | |
295 static const AtomicString& playbackStateWaiting() | |
296 { | |
297 DEFINE_STATIC_LOCAL(AtomicString, waiting, ("waiting", AtomicString::Constru
ctFromLiteral)); | |
298 return waiting; | |
299 } | |
300 | |
301 static const AtomicString& playbackStatePlaying() | |
302 { | |
303 DEFINE_STATIC_LOCAL(AtomicString, playing, ("playing", AtomicString::Constru
ctFromLiteral)); | |
304 return playing; | |
305 } | |
306 | |
307 static const AtomicString& playbackStateEnded() | |
308 { | |
309 DEFINE_STATIC_LOCAL(AtomicString, ended, ("ended", AtomicString::ConstructFr
omLiteral)); | |
310 return ended; | |
311 } | |
312 | |
313 const AtomicString& MediaController::playbackState() const | |
314 { | |
315 switch (m_playbackState) { | |
316 case WAITING: | |
317 return playbackStateWaiting(); | |
318 case PLAYING: | |
319 return playbackStatePlaying(); | |
320 case ENDED: | |
321 return playbackStateEnded(); | |
322 default: | |
323 ASSERT_NOT_REACHED(); | |
324 return nullAtom; | |
325 } | |
326 } | |
327 | |
328 void MediaController::reportControllerState() | |
329 { | |
330 updateReadyState(); | |
331 updatePlaybackState(); | |
332 } | |
333 | |
334 static const AtomicString& eventNameForReadyState(HTMLMediaElement::ReadyState s
tate) | |
335 { | |
336 switch (state) { | |
337 case HTMLMediaElement::HAVE_NOTHING: | |
338 return EventTypeNames::emptied; | |
339 case HTMLMediaElement::HAVE_METADATA: | |
340 return EventTypeNames::loadedmetadata; | |
341 case HTMLMediaElement::HAVE_CURRENT_DATA: | |
342 return EventTypeNames::loadeddata; | |
343 case HTMLMediaElement::HAVE_FUTURE_DATA: | |
344 return EventTypeNames::canplay; | |
345 case HTMLMediaElement::HAVE_ENOUGH_DATA: | |
346 return EventTypeNames::canplaythrough; | |
347 default: | |
348 ASSERT_NOT_REACHED(); | |
349 return nullAtom; | |
350 } | |
351 } | |
352 | |
353 void MediaController::updateReadyState() | |
354 { | |
355 ReadyState oldReadyState = m_readyState; | |
356 ReadyState newReadyState; | |
357 | |
358 if (m_mediaElements.isEmpty()) { | |
359 // If the MediaController has no slaved media elements, let new readines
s state be 0. | |
360 newReadyState = HTMLMediaElement::HAVE_NOTHING; | |
361 } else { | |
362 // Otherwise, let it have the lowest value of the readyState IDL attribu
tes of all of its | |
363 // slaved media elements. | |
364 MediaElementSequence::const_iterator it = m_mediaElements.begin(); | |
365 newReadyState = (*it)->readyState(); | |
366 for (++it; it != m_mediaElements.end(); ++it) | |
367 newReadyState = std::min(newReadyState, (*it)->readyState()); | |
368 } | |
369 | |
370 if (newReadyState == oldReadyState) | |
371 return; | |
372 | |
373 // If the MediaController's most recently reported readiness state is greate
r than new readiness | |
374 // state then queue a task to fire a simple event at the MediaController obj
ect, whose name is the | |
375 // event name corresponding to the value of new readiness state given in the
table below. [omitted] | |
376 if (oldReadyState > newReadyState) { | |
377 scheduleEvent(eventNameForReadyState(newReadyState)); | |
378 return; | |
379 } | |
380 | |
381 // If the MediaController's most recently reported readiness state is less t
han the new readiness | |
382 // state, then run these substeps: | |
383 // 1. Let next state be the MediaController's most recently reported readine
ss state. | |
384 ReadyState nextState = oldReadyState; | |
385 do { | |
386 // 2. Loop: Increment next state by one. | |
387 nextState = static_cast<ReadyState>(nextState + 1); | |
388 // 3. Queue a task to fire a simple event at the MediaController object,
whose name is the | |
389 // event name corresponding to the value of next state given in the tabl
e below. [omitted] | |
390 scheduleEvent(eventNameForReadyState(nextState)); | |
391 // If next state is less than new readiness state, then return to the st
ep labeled loop | |
392 } while (nextState < newReadyState); | |
393 | |
394 // Let the MediaController's most recently reported readiness state be new r
eadiness state. | |
395 m_readyState = newReadyState; | |
396 } | |
397 | |
398 void MediaController::updatePlaybackState() | |
399 { | |
400 PlaybackState oldPlaybackState = m_playbackState; | |
401 PlaybackState newPlaybackState; | |
402 | |
403 // Initialize new playback state by setting it to the state given for the fi
rst matching | |
404 // condition from the following list: | |
405 if (m_mediaElements.isEmpty()) { | |
406 // If the MediaController has no slaved media elements | |
407 // Let new playback state be waiting. | |
408 newPlaybackState = WAITING; | |
409 } else if (hasEnded()) { | |
410 // If all of the MediaController's slaved media elements have ended play
back and the media | |
411 // controller playback rate is positive or zero | |
412 // Let new playback state be ended. | |
413 newPlaybackState = ENDED; | |
414 } else if (isBlocked()) { | |
415 // If the MediaController is a blocked media controller | |
416 // Let new playback state be waiting. | |
417 newPlaybackState = WAITING; | |
418 } else { | |
419 // Otherwise | |
420 // Let new playback state be playing. | |
421 newPlaybackState = PLAYING; | |
422 } | |
423 | |
424 // If the MediaController's most recently reported playback state is not equ
al to new playback state | |
425 if (newPlaybackState == oldPlaybackState) | |
426 return; | |
427 | |
428 // and the new playback state is ended, | |
429 if (newPlaybackState == ENDED) { | |
430 // then queue a task that, if the MediaController object is a playing me
dia controller, and | |
431 // all of the MediaController's slaved media elements have still ended p
layback, and the | |
432 // media controller playback rate is still positive or zero, | |
433 if (!m_paused && hasEnded()) { | |
434 // changes the MediaController object to a paused media controller | |
435 m_paused = true; | |
436 | |
437 // and then fires a simple event named pause at the MediaController
object. | |
438 scheduleEvent(EventTypeNames::pause); | |
439 } | |
440 } | |
441 | |
442 // If the MediaController's most recently reported playback state is not equ
al to new playback state | |
443 // then queue a task to fire a simple event at the MediaController object, w
hose name is playing | |
444 // if new playback state is playing, ended if new playback state is ended, a
nd waiting otherwise. | |
445 AtomicString eventName; | |
446 switch (newPlaybackState) { | |
447 case WAITING: | |
448 eventName = EventTypeNames::waiting; | |
449 m_clock->stop(); | |
450 m_timeupdateTimer.stop(); | |
451 break; | |
452 case ENDED: | |
453 eventName = EventTypeNames::ended; | |
454 m_clock->stop(); | |
455 m_timeupdateTimer.stop(); | |
456 break; | |
457 case PLAYING: | |
458 eventName = EventTypeNames::playing; | |
459 m_clock->start(); | |
460 startTimeupdateTimer(); | |
461 break; | |
462 default: | |
463 ASSERT_NOT_REACHED(); | |
464 } | |
465 scheduleEvent(eventName); | |
466 | |
467 // Let the MediaController's most recently reported playback state be new pl
ayback state. | |
468 m_playbackState = newPlaybackState; | |
469 | |
470 updateMediaElements(); | |
471 } | |
472 | |
473 void MediaController::updateMediaElements() | |
474 { | |
475 for (MediaElementSequence::const_iterator it = m_mediaElements.begin(); it !
= m_mediaElements.end(); ++it) | |
476 (*it)->updatePlayState(); | |
477 } | |
478 | |
479 void MediaController::bringElementUpToSpeed(HTMLMediaElement* element) | |
480 { | |
481 ASSERT(element); | |
482 ASSERT(m_mediaElements.contains(element)); | |
483 | |
484 // When the user agent is to bring a media element up to speed with its new
media controller, | |
485 // it must seek that media element to the MediaController's media controller
position relative | |
486 // to the media element's timeline. | |
487 element->seek(currentTime(), IGNORE_EXCEPTION); | |
488 | |
489 // Update volume to take controller volume and mute into account. | |
490 element->updateVolume(); | |
491 } | |
492 | |
493 bool MediaController::isRestrained() const | |
494 { | |
495 ASSERT(!m_mediaElements.isEmpty()); | |
496 | |
497 // A MediaController is a restrained media controller if the MediaController
is a playing media | |
498 // controller, | |
499 if (m_paused) | |
500 return false; | |
501 | |
502 bool anyAutoplayingAndPaused = false; | |
503 bool allPaused = true; | |
504 for (MediaElementSequence::const_iterator it = m_mediaElements.begin(); it !
= m_mediaElements.end(); ++it) { | |
505 HTMLMediaElement* element = *it; | |
506 | |
507 // and none of its slaved media elements are blocked media elements, | |
508 if (element->isBlocked()) | |
509 return false; | |
510 | |
511 if (element->isAutoplaying() && element->paused()) | |
512 anyAutoplayingAndPaused = true; | |
513 | |
514 if (!element->paused()) | |
515 allPaused = false; | |
516 } | |
517 | |
518 // but either at least one of its slaved media elements whose autoplaying fl
ag is true still has | |
519 // its paused attribute set to true, or, all of its slaved media elements ha
ve their paused | |
520 // attribute set to true. | |
521 return anyAutoplayingAndPaused || allPaused; | |
522 } | |
523 | |
524 bool MediaController::isBlocked() const | |
525 { | |
526 ASSERT(!m_mediaElements.isEmpty()); | |
527 | |
528 // A MediaController is a blocked media controller if the MediaController is
a paused media | |
529 // controller, | |
530 if (m_paused) | |
531 return true; | |
532 | |
533 bool allPaused = true; | |
534 for (MediaElementSequence::const_iterator it = m_mediaElements.begin(); it !
= m_mediaElements.end(); ++it) { | |
535 HTMLMediaElement* element = *it; | |
536 | |
537 // or if any of its slaved media elements are blocked media elements, | |
538 if (element->isBlocked()) | |
539 return true; | |
540 | |
541 // or if any of its slaved media elements whose autoplaying flag is true
still have their | |
542 // paused attribute set to true, | |
543 if (element->isAutoplaying() && element->paused()) | |
544 return true; | |
545 | |
546 if (!element->paused()) | |
547 allPaused = false; | |
548 } | |
549 | |
550 // or if all of its slaved media elements have their paused attribute set to
true. | |
551 return allPaused; | |
552 } | |
553 | |
554 bool MediaController::hasEnded() const | |
555 { | |
556 // If the ... media controller playback rate is positive or zero | |
557 if (m_clock->playRate() < 0) | |
558 return false; | |
559 | |
560 // [and] all of the MediaController's slaved media elements have ended playb
ack ... let new | |
561 // playback state be ended. | |
562 if (m_mediaElements.isEmpty()) | |
563 return false; | |
564 | |
565 bool allHaveEnded = true; | |
566 for (MediaElementSequence::const_iterator it = m_mediaElements.begin(); it !
= m_mediaElements.end(); ++it) { | |
567 if (!(*it)->ended()) | |
568 allHaveEnded = false; | |
569 } | |
570 return allHaveEnded; | |
571 } | |
572 | |
573 void MediaController::scheduleEvent(const AtomicString& eventName) | |
574 { | |
575 m_pendingEventsQueue->enqueueEvent(Event::createCancelable(eventName)); | |
576 } | |
577 | |
578 void MediaController::clearPositionTimerFired(Timer<MediaController>*) | |
579 { | |
580 m_position = MediaPlayer::invalidTime(); | |
581 } | |
582 | |
583 const AtomicString& MediaController::interfaceName() const | |
584 { | |
585 return EventTargetNames::MediaController; | |
586 } | |
587 | |
588 // The spec says to fire periodic timeupdate events (those sent while playing) e
very | |
589 // "15 to 250ms", we choose the slowest frequency | |
590 static const double maxTimeupdateEventFrequency = 0.25; | |
591 | |
592 void MediaController::startTimeupdateTimer() | |
593 { | |
594 if (m_timeupdateTimer.isActive()) | |
595 return; | |
596 | |
597 m_timeupdateTimer.startRepeating(maxTimeupdateEventFrequency, FROM_HERE); | |
598 } | |
599 | |
600 void MediaController::timeupdateTimerFired(Timer<MediaController>*) | |
601 { | |
602 scheduleTimeupdateEvent(); | |
603 } | |
604 | |
605 void MediaController::scheduleTimeupdateEvent() | |
606 { | |
607 double now = WTF::currentTime(); | |
608 double timedelta = now - m_previousTimeupdateTime; | |
609 | |
610 if (timedelta < maxTimeupdateEventFrequency) | |
611 return; | |
612 | |
613 scheduleEvent(EventTypeNames::timeupdate); | |
614 m_previousTimeupdateTime = now; | |
615 } | |
616 | |
617 void MediaController::trace(Visitor* visitor) | |
618 { | |
619 #if ENABLE(OILPAN) | |
620 visitor->trace(m_mediaElements); | |
621 visitor->trace(m_pendingEventsQueue); | |
622 visitor->trace(m_executionContext); | |
623 #endif | |
624 EventTargetWithInlineData::trace(visitor); | |
625 } | |
626 | |
627 } | |
OLD | NEW |