no timeupdate events emitted for media controller
https://bugs.webkit.org/show_bug.cgi?id=93745

Reviewed by Eric Carlson.

Source/WebCore:

Generate timeupdate events while the current position is changing.

Test: media/media-controller-timeupdate.html

Enforce the spec requirement that the timeupdate event is fired no more often
than every 250ms.
* html/MediaController.cpp:
(MediaController::scheduleTimeupdateEvent):

Add a periodic firing timer to generate timeupdate events during playback.
* html/MediaController.cpp:
(MediaController::startTimeupdateTimer):
(MediaController::timeupdateTimerFired):

* html/MediaController.cpp:
(MediaController::MediaController): Initialize m_previousTimeupdateTime.
(MediaController::setCurrentTime): Call scheduleTimeUpdateEvent.
(MediaController::updatePlaybackState): Start and stop the timeupdate timer.
* html/MediaController.h:

LayoutTests:

New test checking that the timeupdate event is emmitted correctly during playback.

* media/media-controller-timeupdate-expected.txt: Added.
* media/media-controller-timeupdate.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@125337 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 50a1059..1331677 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,15 @@
+2012-08-10  Jer Noble  <jer.noble@apple.com>
+
+        no timeupdate events emitted for media controller
+        https://bugs.webkit.org/show_bug.cgi?id=93745
+
+        Reviewed by Eric Carlson.
+
+        New test checking that the timeupdate event is emmitted correctly during playback.
+
+        * media/media-controller-timeupdate-expected.txt: Added.
+        * media/media-controller-timeupdate.html: Added.
+
 2012-08-09  Jeffrey Pfau  <jpfau@apple.com>
 
         Allow blocking of third-party localStorage and sessionStorage
diff --git a/LayoutTests/media/media-controller-timeupdate-expected.txt b/LayoutTests/media/media-controller-timeupdate-expected.txt
new file mode 100644
index 0000000..b221007
--- /dev/null
+++ b/LayoutTests/media/media-controller-timeupdate-expected.txt
@@ -0,0 +1,5 @@
+EVENT(canplay)
+RUN(video.play)
+EVENT(timeupdate)
+END OF TEST
+
diff --git a/LayoutTests/media/media-controller-timeupdate.html b/LayoutTests/media/media-controller-timeupdate.html
new file mode 100644
index 0000000..e7292ee
--- /dev/null
+++ b/LayoutTests/media/media-controller-timeupdate.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>MediaController - timeupdate test</title>
+    <script src=video-test.js></script>
+    <script src=media-file.js></script>
+    <script>
+        var video;
+
+        var start = function() {
+            findMediaElement();
+            
+            waitForEvent('canplay', canplay);
+            video.src = findMediaFile("video", "content/test");
+        };
+        
+        var canplay = function() {
+            waitForEventAndEnd('timeupdate');
+            run('video.play');
+        };
+    </script>
+</head>
+<body>
+    <body onload="start()">
+        <video id="video" mediaGroup="group" controls autoplay></video>
+    </body>
+</body>
+</html>
\ No newline at end of file
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 0bf473a..649e277 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,30 @@
+2012-08-10  Jer Noble  <jer.noble@apple.com>
+
+        no timeupdate events emitted for media controller
+        https://bugs.webkit.org/show_bug.cgi?id=93745
+
+        Reviewed by Eric Carlson.
+
+        Generate timeupdate events while the current position is changing.
+
+        Test: media/media-controller-timeupdate.html
+
+        Enforce the spec requirement that the timeupdate event is fired no more often
+        than every 250ms.
+        * html/MediaController.cpp:
+        (MediaController::scheduleTimeupdateEvent):
+
+        Add a periodic firing timer to generate timeupdate events during playback.
+        * html/MediaController.cpp:
+        (MediaController::startTimeupdateTimer):
+        (MediaController::timeupdateTimerFired):
+
+        * html/MediaController.cpp:
+        (MediaController::MediaController): Initialize m_previousTimeupdateTime.
+        (MediaController::setCurrentTime): Call scheduleTimeUpdateEvent.
+        (MediaController::updatePlaybackState): Start and stop the timeupdate timer.
+        * html/MediaController.h:
+        
 2012-08-09  Jeffrey Pfau  <jpfau@apple.com>
 
         Allow blocking of third-party localStorage and sessionStorage
diff --git a/Source/WebCore/html/MediaController.cpp b/Source/WebCore/html/MediaController.cpp
index 39fd09d..d38f9dd 100644
--- a/Source/WebCore/html/MediaController.cpp
+++ b/Source/WebCore/html/MediaController.cpp
@@ -56,6 +56,8 @@
     , m_closedCaptionsVisible(false)
     , m_clock(Clock::create())
     , m_scriptExecutionContext(context)
+    , m_timeupdateTimer(this, &MediaController::timeupdateTimerFired)
+    , m_previousTimeupdateTime(0)
 {
 }
 
@@ -171,6 +173,8 @@
     // Seek each slaved media element to the new playback position relative to the media element timeline.
     for (size_t index = 0; index < m_mediaElements.size(); ++index)
         m_mediaElements[index]->seek(time, code);
+
+    scheduleTimeupdateEvent();
 }
 
 void MediaController::play()
@@ -395,14 +399,17 @@
     case WAITING:
         eventName = eventNames().waitingEvent;
         m_clock->stop();
+        m_timeupdateTimer.stop();
         break;
     case ENDED:
         eventName = eventNames().endedEvent;
         m_clock->stop();
+        m_timeupdateTimer.stop();
         break;
     case PLAYING:
         eventName = eventNames().playingEvent;
         m_clock->start();
+        startTimeupdateTimer();
         break;
     default:
         ASSERT_NOT_REACHED();
@@ -605,4 +612,33 @@
     return eventNames().interfaceForMediaController;
 }
 
+// The spec says to fire periodic timeupdate events (those sent while playing) every
+// "15 to 250ms", we choose the slowest frequency
+static const double maxTimeupdateEventFrequency = 0.25;
+
+void MediaController::startTimeupdateTimer()
+{
+    if (m_timeupdateTimer.isActive())
+        return;
+
+    m_timeupdateTimer.startRepeating(maxTimeupdateEventFrequency);
+}
+
+void MediaController::timeupdateTimerFired(Timer<MediaController>*)
+{
+    scheduleTimeupdateEvent();
+}
+
+void MediaController::scheduleTimeupdateEvent()
+{
+    double now = WTF::currentTime();
+    double timedelta = now - m_previousTimeupdateTime;
+
+    if (timedelta < maxTimeupdateEventFrequency)
+        return;
+
+    scheduleEvent(eventNames().timeupdateEvent);
+    m_previousTimeupdateTime = now;
+}
+
 #endif
diff --git a/Source/WebCore/html/MediaController.h b/Source/WebCore/html/MediaController.h
index d32b712..d293ccb 100644
--- a/Source/WebCore/html/MediaController.h
+++ b/Source/WebCore/html/MediaController.h
@@ -125,6 +125,9 @@
     void asyncEventTimerFired(Timer<MediaController>*);
     void clearPositionTimerFired(Timer<MediaController>*);
     bool hasEnded() const;
+    void scheduleTimeupdateEvent();
+    void timeupdateTimerFired(Timer<MediaController>*);
+    void startTimeupdateTimer();
 
     // EventTarget
     virtual void refEventTarget() { ref(); }
@@ -152,6 +155,8 @@
     bool m_closedCaptionsVisible;
     PassRefPtr<Clock> m_clock;
     ScriptExecutionContext* m_scriptExecutionContext;
+    Timer<MediaController> m_timeupdateTimer;
+    double m_previousTimeupdateTime;
 };
 
 } // namespace WebCore