WebCore:
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Nov 2007 20:08:27 +0000 (20:08 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Nov 2007 20:08:27 +0000 (20:08 +0000)
        Reviewed by Adele.

        Fix that 'timeupdate' and 'waiting' events were never dispatched.

        Add explicit m_paused attribute instead of trying to derive paused state from
        underlying media. Call updatePlayState() to start/stop media playback
        when any attribute that affects active playback state changes. This matches
        specification text.

        Test: http/tests/media/video-play-stall.html

        * html/HTMLMediaElement.cpp:
        (WebCore::HTMLMediaElement::HTMLMediaElement):
        (WebCore::HTMLMediaElement::setReadyState):
        (WebCore::HTMLMediaElement::paused):
        (WebCore::HTMLMediaElement::play):
        (WebCore::HTMLMediaElement::pause):
        (WebCore::HTMLMediaElement::checkIfSeekNeeded):
        (WebCore::HTMLMediaElement::movieDidEnd):
        (WebCore::HTMLMediaElement::updatePlayState):
        * html/HTMLMediaElement.h:

LayoutTests:

        Reviewed by Adele.

        - add HTTP media test for stalling load
        - update tests that don't specifically test autoplay feature to not use autoplay
          attribute since playback may start before event listeners are registered

        * http/tests/media: Added.
        * http/tests/media/video-load-and-stall.cgi: Added.
        * http/tests/media/video-play-stall-expected.txt: Added.
        * http/tests/media/video-play-stall.html: Added.
        * media/video-autoplay.html:
        * media/video-dom-loopstart.html:
        * media/video-end.html:
        * media/video-loopcount.html:
        * media/video-loopend.html:
        * media/video-loopstart.html:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@27758 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/media/video-load-and-stall.cgi [new file with mode: 0755]
LayoutTests/http/tests/media/video-play-stall-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/media/video-play-stall.html [new file with mode: 0644]
LayoutTests/media/video-autoplay.html
LayoutTests/media/video-dom-loopstart.html
LayoutTests/media/video-end.html
LayoutTests/media/video-loopcount.html
LayoutTests/media/video-loopend.html
LayoutTests/media/video-loopstart.html
WebCore/ChangeLog
WebCore/html/HTMLMediaElement.cpp
WebCore/html/HTMLMediaElement.h

index a8290ea..5076313 100644 (file)
@@ -1,3 +1,22 @@
+2007-11-12  Antti Koivisto  <antti@apple.com>
+
+        Reviewed by Adele.
+        
+        - add HTTP media test for stalling load
+        - update tests that don't specifically test autoplay feature to not use autoplay 
+          attribute since playback may start before event listeners are registered
+
+        * http/tests/media: Added.
+        * http/tests/media/video-load-and-stall.cgi: Added.
+        * http/tests/media/video-play-stall-expected.txt: Added.
+        * http/tests/media/video-play-stall.html: Added.
+        * media/video-autoplay.html:
+        * media/video-dom-loopstart.html:
+        * media/video-end.html:
+        * media/video-loopcount.html:
+        * media/video-loopend.html:
+        * media/video-loopstart.html:
+
 2007-11-13  Darin Adler  <darin@apple.com>
 
         Reviewed by Geoff.
diff --git a/LayoutTests/http/tests/media/video-load-and-stall.cgi b/LayoutTests/http/tests/media/video-load-and-stall.cgi
new file mode 100755 (executable)
index 0000000..9c2c134
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/perl -w
+
+use CGI;
+use File::stat;
+
+$query = new CGI;
+$name = $query->param('name');
+$stallAt = $query->param('stallAt');
+
+my $filesize = stat($name)->size;
+print "Content-type: video/mp4\n"; 
+print "Content-Length: " . $filesize . "\n\n";
+
+open FILE, $name or die;
+binmode FILE;
+$total = 0;
+my ($buf, $data, $n);
+while (($n = read FILE, $data, 1024) != 0) {
+    $total += $n;
+    if ($total > $stallAt) {
+        close(FILE);
+        return;
+    }
+    print $data;
+}
+close(FILE);
diff --git a/LayoutTests/http/tests/media/video-play-stall-expected.txt b/LayoutTests/http/tests/media/video-play-stall-expected.txt
new file mode 100644 (file)
index 0000000..7ddb9cb
--- /dev/null
@@ -0,0 +1,12 @@
+Test that dataunavailable, timeupdate and waiting events are sent when media load stalls in the middle.
+
+EVENT(durationchange)
+EVENT(loadedmetadata)
+EVENT(loadedfirstframe)
+EVENT(canshowcurrentframe)
+EVENT(canplay)
+EVENT(dataunavailable)
+EVENT(timeupdate)
+EVENT(waiting)
+END OF TEST
+
diff --git a/LayoutTests/http/tests/media/video-play-stall.html b/LayoutTests/http/tests/media/video-play-stall.html
new file mode 100644 (file)
index 0000000..4db5129
--- /dev/null
@@ -0,0 +1,15 @@
+<video src="http://127.0.0.1:8000/media/video-load-and-stall.cgi?name=../../../media/content/test.mp4&stallAt=80000"></video>
+<p>Test that dataunavailable, timeupdate and waiting events are sent when media load stalls in the middle.</p>
+<script src=../../../media/video-test.js></script>
+<script>
+waitForEvent('durationchange');
+waitForEvent('loadedmetadata');
+waitForEvent('loadedfirstframe');
+waitForEvent('canshowcurrentframe');
+waitForEvent('canplay', function () {
+    waitForEvent('dataunavailable');
+    waitForEvent('timeupdate');
+    waitForEventAndEnd('waiting');
+} );
+video.play();
+</script>
index b52710f..d0f6eb7 100644 (file)
@@ -1,7 +1,8 @@
-<video src=content/test.mp4 autoplay></video>
+<video autoplay></video>
 <script src=video-test.js></script>
 <script>
 test("video.autoplay");
 test("video.getAttribute('autoplay') != null");
 waitForEventTestAndEnd('play', "!video.paused");
+video.src = "content/test.mp4";
 </script>
index 2d21195..5cd54e1 100644 (file)
@@ -1,4 +1,4 @@
-<video src=content/test.mp4 loopcount=2 autoplay></video>
+<video src=content/test.mp4 loopcount=2></video>
 <script src=video-test.js></script>
 <script>
 video.loopStart = 1.0;
@@ -6,4 +6,5 @@ test("video.loopStart==1.0");
 test("video.getAttribute('loopstart') == '1s'");
 waitForEvent('play', function () { video.currentTime = 500; });
 waitForEventTestAndEnd('timeupdate', "video.currentTime.toFixed(1) && video.currentLoop==1");
+video.play();
 </script>
index d9874f9..1f8d4e6 100644 (file)
@@ -1,4 +1,4 @@
-<video autoplay src=content/test.mp4 end=0.5s></video>
+<video src=content/test.mp4 end=0.5s></video>
 <script src=video-test.js></script>
 <script>
 test("!video.ended");
@@ -11,4 +11,5 @@ waitForEvent('ended',
         endTest();
     }
 );
+video.play();
 </script>
index 48820c1..aedc950 100644 (file)
@@ -1,7 +1,8 @@
-<video src=content/test.mp4 loopcount=2 loopend=0.2s end=0.2s autoplay></video>
+<video src=content/test.mp4 loopcount=2 loopend=0.2s end=0.2s></video>
 <script src=video-test.js></script>
 <script>
 test("video.loopCount == 2");
 test("video.currentLoop == 0");
 waitForEventTestAndEnd('ended', "video.currentLoop == 1");
+video.play();
 </script>
index ef99976..00cfeb1 100644 (file)
@@ -1,8 +1,9 @@
-<video src=content/test.mp4 loopcount=2 autoplay></video>
+<video src=content/test.mp4 loopcount=2></video>
 <script src=video-test.js></script>
 <script>
 video.loopEnd = 0.5;
 test("video.loopEnd==0.5");
 setTimeout(function () { test("video.currentTime<=0.5"); }, 2000);
 waitForEventTestAndEnd('timeupdate', "video.currentTime.toFixed(1) == 0 && video.currentLoop==1");
+video.play();
 </script>
index 2aff30b..7134f10 100644 (file)
@@ -1,7 +1,8 @@
-<video src=content/test.mp4 loopcount=2 loopstart=1s autoplay></video>
+<video src=content/test.mp4 loopcount=2 loopstart=1s></video>
 <script src=video-test.js></script>
 <script>
 test("video.loopStart==1.0");
 waitForEvent('play', function () { video.currentTime = 500; });
 waitForEventTestAndEnd('timeupdate', "video.currentTime.toFixed(1) == 1.0 && video.currentLoop==1");
+video.play();
 </script>
index f5b4f53..e1c9ea3 100644 (file)
@@ -1,3 +1,27 @@
+2007-11-12  Antti Koivisto  <antti@apple.com>
+
+        Reviewed by Adele.
+
+        Fix that 'timeupdate' and 'waiting' events were never dispatched.
+        
+        Add explicit m_paused attribute instead of trying to derive paused state from
+        underlying media. Call updatePlayState() to start/stop media playback
+        when any attribute that affects active playback state changes. This matches 
+        specification text.
+        
+        Test: http/tests/media/video-play-stall.html
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::HTMLMediaElement):
+        (WebCore::HTMLMediaElement::setReadyState):
+        (WebCore::HTMLMediaElement::paused):
+        (WebCore::HTMLMediaElement::play):
+        (WebCore::HTMLMediaElement::pause):
+        (WebCore::HTMLMediaElement::checkIfSeekNeeded):
+        (WebCore::HTMLMediaElement::movieDidEnd):
+        (WebCore::HTMLMediaElement::updatePlayState):
+        * html/HTMLMediaElement.h:
+
 2007-11-13  John Sullivan  <sullivan@apple.com>
 
         Reviewed by Darin.
index d621a93..b1059b9 100644 (file)
@@ -71,6 +71,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc)
     , m_currentLoop(0)
     , m_volume(0.5f)
     , m_muted(false)
+    , m_paused(true)
     , m_previousProgress(0)
     , m_previousProgressTime(numeric_limits<double>::max())
     , m_sentStalledEvent(false)
@@ -259,6 +260,7 @@ void HTMLMediaElement::load(ExceptionCode& ec)
     if (networkState() != EMPTY) {
         m_networkState = EMPTY;
         m_readyState = DATA_UNAVAILABLE;
+        m_paused = true;
         if (m_movie) {
             m_movie->pause();
             m_movie->seek(0);
@@ -435,11 +437,12 @@ void HTMLMediaElement::setReadyState(ReadyState state)
         dispatchHTMLEvent(canplayEvent, false, true);
     } else if (state == CAN_PLAY_THROUGH) {
         dispatchHTMLEvent(canplaythroughEvent, false, true);
-        if (m_autoplaying && paused() && autoplay()) {
-            m_movie->play();
+        if (m_autoplaying && m_paused && autoplay()) {
+            m_paused = false;
             dispatchHTMLEvent(playEvent, false, true);
         }
     }
+    updatePlayState();
 }
 
 void HTMLMediaElement::progressEventTimerFired(Timer<HTMLMediaElement>*)
@@ -545,7 +548,7 @@ float HTMLMediaElement::duration() const
 
 bool HTMLMediaElement::paused() const
 {
-    return m_movie ? m_movie->paused() : true;
+    return m_paused;
 }
 
 float HTMLMediaElement::defaultPlaybackRate() const
@@ -613,8 +616,9 @@ void HTMLMediaElement::play(ExceptionCode& ec)
     }
     setPlaybackRate(defaultPlaybackRate(), unused);
     
-    if (m_movie->paused()) {
-        m_movie->play();
+    if (m_paused) {
+        m_paused = false;
+        updatePlayState();
         dispatchEventAsync(playEvent);
     }
 
@@ -631,8 +635,9 @@ void HTMLMediaElement::pause(ExceptionCode& ec)
             return;
     }
 
-    if (!m_movie->paused()) {
-        m_movie->pause();
+    if (!m_paused) {
+        m_paused = true;
+        updatePlayState();
         dispatchEventAsync(timeupdateEvent);
         dispatchEventAsync(pauseEvent);
     }
@@ -818,6 +823,8 @@ void HTMLMediaElement::checkIfSeekNeeded()
     // 6
     if (m_currentLoop == loopCount() - 1 && time > effectiveEnd())
         seek(effectiveEnd(), ec);
+
+    updatePlayState();
 }
 
 void HTMLMediaElement::movieVolumeChanged(Movie*)
@@ -837,8 +844,7 @@ void HTMLMediaElement::movieDidEnd(Movie*)
         m_movie->seek(effectiveLoopStart());
         m_currentLoop++;
         m_movie->setEndTime(m_currentLoop == loopCount() - 1 ? effectiveEnd() : effectiveLoopEnd());
-        if (m_movie)
-            m_movie->play();
+        updatePlayState();
         dispatchHTMLEvent(timeupdateEvent, false, true);
     }
     
@@ -967,6 +973,17 @@ bool HTMLMediaElement::endedPlayback() const
     return networkState() >= LOADED_METADATA && currentTime() >= effectiveEnd() && currentLoop() == loopCount() - 1;
 }
 
+void HTMLMediaElement::updatePlayState()
+{
+    if (!m_movie)
+        return;
+    bool shouldBePlaying = activelyPlaying();
+    if (shouldBePlaying && m_movie->paused())
+        m_movie->play();
+    else if (!shouldBePlaying && !m_movie->paused())
+        m_movie->pause();
+}
+    
 void HTMLMediaElement::willSaveToCache()
 {
     // 3.14.9.4. Loading the media resource
index d7bec74..656041c 100644 (file)
@@ -152,6 +152,7 @@ private:
     void checkIfSeekNeeded();
     
     String pickMedia();
+    void updatePlayState();
     float effectiveStart() const;
     float effectiveEnd() const;
     float effectiveLoopStart() const;
@@ -182,6 +183,7 @@ protected:
     float m_volume;
     bool m_muted;
     
+    bool m_paused;
     bool m_seeking;
     
     unsigned m_previousProgress;