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/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