WPT test MediaStream-MediaElement-srcObject.https.html times out
https://bugs.webkit.org/show_bug.cgi?id=204762
<rdar://problem/57567671>

Reviewed by youenn fablet.

LayoutTests/imported/w3c:

* web-platform-tests/mediacapture-streams/MediaStream-MediaElement-firstframe.https-expected.txt:
* web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https-expected.txt:
* web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html:

Source/WebCore:

No new tests, these changes fix existing tests.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::prepareForLoad): Check hasMediaStreamSrcObject() instead of
m_mediaStreamSrcObject so we behave correctly when a MediaStream is cleared by setting srcObject to null.
(WebCore::HTMLMediaElement::loadResource): Ditto.
(WebCore::HTMLMediaElement::seekWithTolerance): Return early if seeking isn't allowed.
(WebCore::HTMLMediaElement::defaultPlaybackRate const): Check hasMediaStreamSrcObject() instead
of m_mediaStreamSrcObject.
(WebCore::HTMLMediaElement::setDefaultPlaybackRate): Ditto.
(WebCore::HTMLMediaElement::playbackRate const): Ditto.
(WebCore::HTMLMediaElement::setPlaybackRate): Ditto.
(WebCore::HTMLMediaElement::ended const): Ditto.
(WebCore::HTMLMediaElement::preload const): Ditto.
(WebCore::HTMLMediaElement::setPreload): Ditto.
(WebCore::HTMLMediaElement::mediaPlayerTimeChanged): Don't send an 'ended' event for a MediaStream.
(WebCore::HTMLMediaElement::clearMediaPlayer): Don't check m_settingMediaStreamSrcObject, it
is never set.
* html/HTMLMediaElement.h:

* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h: Add m_lastReportedTime.
* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::durationMediaTime const): Return last reported
time after the stream ends.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::currentMediaTime const): Ditto. Set m_lastReportedTime.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::currentReadyState): Don't return HaveNothing
for an inactive stream. Return HaveMetadata for an stream that has either ended or is waiting
for the first video frame.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::activeStatusChanged): Send duration changed when
a stream ends.

LayoutTests:

* TestExpectations: Mark imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html
as expected to fail because the failure message logs media times as floats, so the values
logged are always different.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@253148 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 6fd02ec..cf0bff9 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,15 @@
+2019-12-05  Eric Carlson  <eric.carlson@apple.com>
+
+        WPT test MediaStream-MediaElement-srcObject.https.html times out
+        https://bugs.webkit.org/show_bug.cgi?id=204762
+        <rdar://problem/57567671>
+
+        Reviewed by youenn fablet.
+
+        * TestExpectations: Mark imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html
+        as expected to fail because the failure message logs media times as floats, so the values
+        logged are always different.
+
 2019-12-05  youenn fablet  <youenn@apple.com>
 
         getStats() promise never rejects nor resolves when peer connection state is closed.
diff --git a/LayoutTests/TestExpectations b/LayoutTests/TestExpectations
index 84b4e1f..7cfa27a 100644
--- a/LayoutTests/TestExpectations
+++ b/LayoutTests/TestExpectations
@@ -3878,3 +3878,7 @@
 webgl/1.0.3/conformance/textures/copy-tex-image-2d-formats.html [ Skip ]
 webgl/1.0.3/conformance/canvas/rapid-resizing.html [ Skip ]
 webgl/1.0.3/conformance/extensions/webgl-draw-buffers.html [ Skip ]
+
+# Parts of this test are expected to fail, but the failure message logs media times as floats so it is not
+# possible to land "good" results.
+imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html [ Failure ]
diff --git a/LayoutTests/imported/w3c/ChangeLog b/LayoutTests/imported/w3c/ChangeLog
index 3134414..3752a33 100644
--- a/LayoutTests/imported/w3c/ChangeLog
+++ b/LayoutTests/imported/w3c/ChangeLog
@@ -1,3 +1,15 @@
+2019-12-05  Eric Carlson  <eric.carlson@apple.com>
+
+        WPT test MediaStream-MediaElement-srcObject.https.html times out
+        https://bugs.webkit.org/show_bug.cgi?id=204762
+        <rdar://problem/57567671>
+
+        Reviewed by youenn fablet.
+
+        * web-platform-tests/mediacapture-streams/MediaStream-MediaElement-firstframe.https-expected.txt:
+        * web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https-expected.txt:
+        * web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html:
+
 2019-12-04  Alexey Shvayka  <shvaikalesh@gmail.com>
 
         Non-callable "handleEvent" property is silently ignored
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-firstframe.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-firstframe.https-expected.txt
index 9b2bc2b..36e2e7f 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-firstframe.https-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-firstframe.https-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE MESSAGE: line 3082: Error: assert_unreached: Got unexpected event resize Reached unreachable code
 When prompted, accept to share your video stream.
 
 Description
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https-expected.txt
index 293f7c2..e8233e6 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https-expected.txt
@@ -6,22 +6,20 @@
 
 
 
-Harness Error (TIMEOUT), message = null
-
 PASS Tests that a MediaStream can be assigned to a video element with srcObject 
 PASS Tests that a MediaStream assigned to a video element is not seekable 
 PASS Tests that a MediaStream assigned to a video element is in readyState HAVE_NOTHING initially 
-TIMEOUT Tests that a MediaStream assigned to a video element has expected duration Test timed out
-NOTRUN Tests that a video element with a MediaStream assigned is not preloaded 
-NOTRUN Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is identical) 
-NOTRUN Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is different) 
-NOTRUN Tests that a media element with an assigned MediaStream reports the played attribute as expected 
-NOTRUN Tests that a media element with an assigned MediaStream reports the currentTime attribute as expected 
-NOTRUN Tests that a media element with an assigned MediaStream starts its timeline at 0 regardless of when the MediaStream was created 
-NOTRUN Tests that a media element with an assigned MediaStream does not advance currentTime while paused 
-NOTRUN Tests that the loop attribute has no effect on a media element with an assigned MediaStream 
-NOTRUN Tests that a media element with an assigned MediaStream ends when the MediaStream becomes inactive through tracks ending 
-NOTRUN Tests that an audio element with an assigned MediaStream ends when the MediaStream becomes inaudible through audio tracks ending 
-NOTRUN Tests that a media element with an assigned MediaStream ends when the MediaStream becomes inactive through track removal 
-NOTRUN Tests that an audio element with an assigned MediaStream ends when the MediaStream becomes inaudible through track removal 
+PASS Tests that a MediaStream assigned to a video element has expected duration 
+PASS Tests that a video element with a MediaStream assigned is not preloaded 
+PASS Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is identical) 
+PASS Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is different) 
+FAIL Tests that a media element with an assigned MediaStream reports the played attribute as expected assert_equals: A MediaStream's end MUST return the last known currentTime expected 0.252313446 but got 0.252291624
+FAIL Tests that a media element with an assigned MediaStream reports the currentTime attribute as expected assert_equals: The UA MUST ignore attempts to set the currentTime attribute (restart) expected 0.250999782 but got 0.251026206
+PASS Tests that a media element with an assigned MediaStream starts its timeline at 0 regardless of when the MediaStream was created 
+FAIL Tests that a media element with an assigned MediaStream does not advance currentTime while paused assert_between_exclusive: currentTime does not skip ahead after pause expected a number greater than 0 and less than 0.5 but got 0.755360896
+PASS Tests that the loop attribute has no effect on a media element with an assigned MediaStream 
+PASS Tests that a media element with an assigned MediaStream ends when the MediaStream becomes inactive through tracks ending 
+FAIL Tests that an audio element with an assigned MediaStream ends when the MediaStream becomes inaudible through audio tracks ending assert_true: HTMLAudioElement becomes ended asynchronously when its MediaStream provider becomes inaudible expected true got false
+PASS Tests that a media element with an assigned MediaStream ends when the MediaStream becomes inactive through track removal 
+FAIL Tests that an audio element with an assigned MediaStream ends when the MediaStream becomes inaudible through track removal assert_true: HTMLAudioElement becomes ended asynchronously when its MediaStream provider becomes inaudible expected true got false
 
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html
index 790f73a..7f5fa5d 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html
+++ b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html
@@ -24,7 +24,7 @@
 
 function queueTask(f) {
   window.onmessage = f;
-  window.postMessage("hi");
+  window.postMessage("hi", "*");
 }
 
 promise_test(async t => {
diff --git a/LayoutTests/imported/w3c/web-platform-tests/webrtc/simplecall-no-ssrcs.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/webrtc/simplecall-no-ssrcs.https-expected.txt
index cf2bf92..123f8d0 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/webrtc/simplecall-no-ssrcs.https-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/webrtc/simplecall-no-ssrcs.https-expected.txt
@@ -1,4 +1,4 @@
 
 PASS Can set up a basic WebRTC call without announcing ssrcs. 
- 
+  
 
diff --git a/LayoutTests/imported/w3c/web-platform-tests/webrtc/simplecall.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/webrtc/simplecall.https-expected.txt
index 3158558..fa93a84 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/webrtc/simplecall.https-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/webrtc/simplecall.https-expected.txt
@@ -1,4 +1,4 @@
 
 PASS Can set up a basic WebRTC call. 
- 
+  
 
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 4089c91..426bcae 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,42 @@
+2019-12-05  Eric Carlson  <eric.carlson@apple.com>
+
+        WPT test MediaStream-MediaElement-srcObject.https.html times out
+        https://bugs.webkit.org/show_bug.cgi?id=204762
+        <rdar://problem/57567671>
+
+        Reviewed by youenn fablet.
+
+        No new tests, these changes fix existing tests.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::prepareForLoad): Check hasMediaStreamSrcObject() instead of
+        m_mediaStreamSrcObject so we behave correctly when a MediaStream is cleared by setting srcObject to null.
+        (WebCore::HTMLMediaElement::loadResource): Ditto.
+        (WebCore::HTMLMediaElement::seekWithTolerance): Return early if seeking isn't allowed.
+        (WebCore::HTMLMediaElement::defaultPlaybackRate const): Check hasMediaStreamSrcObject() instead 
+        of m_mediaStreamSrcObject.
+        (WebCore::HTMLMediaElement::setDefaultPlaybackRate): Ditto.
+        (WebCore::HTMLMediaElement::playbackRate const): Ditto.
+        (WebCore::HTMLMediaElement::setPlaybackRate): Ditto.
+        (WebCore::HTMLMediaElement::ended const): Ditto.
+        (WebCore::HTMLMediaElement::preload const): Ditto.
+        (WebCore::HTMLMediaElement::setPreload): Ditto.
+        (WebCore::HTMLMediaElement::mediaPlayerTimeChanged): Don't send an 'ended' event for a MediaStream.
+        (WebCore::HTMLMediaElement::clearMediaPlayer): Don't check m_settingMediaStreamSrcObject, it 
+        is never set.
+        * html/HTMLMediaElement.h:
+
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h: Add m_lastReportedTime.
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm:
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::durationMediaTime const): Return last reported
+        time after the stream ends.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::currentMediaTime const): Ditto. Set m_lastReportedTime.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::currentReadyState): Don't return HaveNothing
+        for an inactive stream. Return HaveMetadata for an stream that has either ended or is waiting
+        for the first video frame.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::activeStatusChanged): Send duration changed when
+        a stream ends.
+
 2019-12-05  Zalan Bujtas  <zalan@apple.com>
 
         [LFC][IFC] Move trailing trimming logic to LineBuilder::TrimmableContent
diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp
index 37dfcd7..e7da02c 100644
--- a/Source/WebCore/html/HTMLMediaElement.cpp
+++ b/Source/WebCore/html/HTMLMediaElement.cpp
@@ -1212,6 +1212,9 @@
     m_havePreparedToPlay = false;
     m_displayMode = Unknown;
     m_currentSrc = URL();
+#if ENABLE(MEDIA_STREAM)
+    m_mediaStreamSrcObject = nullptr;
+#endif
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
     m_failedToPlayToWirelessTarget = false;
@@ -1600,7 +1603,7 @@
     }
 #endif
 #if ENABLE(MEDIA_STREAM)
-    if (!loadAttempted && m_mediaStreamSrcObject) {
+    if (!loadAttempted && hasMediaStreamSrcObject()) {
         loadAttempted = true;
         ALWAYS_LOG(LOGIDENTIFIER, "loading media stream blob");
         if (!m_player->load(m_mediaStreamSrcObject->privateStream()))
@@ -2999,6 +3002,9 @@
     if (m_readyState == HAVE_NOTHING || !m_player)
         return;
 
+    if (!supportsSeeking())
+        return;
+
     // If the media engine has been told to postpone loading data, let it go ahead now.
     if (m_preload < MediaPlayer::Auto && m_readyState < HAVE_FUTURE_DATA)
         prepareToPlay();
@@ -3339,7 +3345,7 @@
     // A MediaStream is not seekable. Therefore, this attribute must always have the
     // value 1.0 and any attempt to alter it must be ignored. Note that this also means
     // that the ratechange event will not fire.
-    if (m_mediaStreamSrcObject)
+    if (hasMediaStreamSrcObject())
         return 1;
 #endif
 
@@ -3354,7 +3360,7 @@
     // A MediaStream is not seekable. Therefore, this attribute must always have the
     // value 1.0 and any attempt to alter it must be ignored. Note that this also means
     // that the ratechange event will not fire.
-    if (m_mediaStreamSrcObject)
+    if (hasMediaStreamSrcObject())
         return;
 #endif
 
@@ -3383,7 +3389,7 @@
     // "playbackRate" - A MediaStream is not seekable. Therefore, this attribute must always
     // have the value 1.0 and any attempt to alter it must be ignored. Note that this also
     // means that the ratechange event will not fire.
-    if (m_mediaStreamSrcObject)
+    if (hasMediaStreamSrcObject())
         return 1;
 #endif
 
@@ -3399,7 +3405,7 @@
     // "playbackRate" - A MediaStream is not seekable. Therefore, this attribute must always
     // have the value 1.0 and any attempt to alter it must be ignored. Note that this also
     // means that the ratechange event will not fire.
-    if (m_mediaStreamSrcObject)
+    if (hasMediaStreamSrcObject())
         return;
 #endif
 
@@ -3443,7 +3449,7 @@
     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
     // When the MediaStream state moves from the active to the inactive state, the User Agent
     // must raise an ended event on the HTMLMediaElement and set its ended attribute to true.
-    if (m_mediaStreamSrcObject && m_player && m_player->ended())
+    if (hasMediaStreamSrcObject() && m_player && m_player->ended())
         return true;
 #endif
 
@@ -3463,7 +3469,7 @@
 #if ENABLE(MEDIA_STREAM)
     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
     // "preload" - On getting: none. On setting: ignored.
-    if (m_mediaStreamSrcObject)
+    if (hasMediaStreamSrcObject())
         return "none"_s;
 #endif
 
@@ -3486,7 +3492,7 @@
 #if ENABLE(MEDIA_STREAM)
     // http://w3c.github.io/mediacapture-main/#mediastreams-in-media-elements
     // "preload" - On getting: none. On setting: ignored.
-    if (m_mediaStreamSrcObject)
+    if (hasMediaStreamSrcObject())
         return;
 #endif
 
@@ -3695,6 +3701,16 @@
 
 #endif
 
+bool HTMLMediaElement::canLoop() const
+{
+#if ENABLE(MEDIA_STREAM)
+    if (hasMediaStreamSrcObject())
+        return false;
+#endif
+
+    return !m_mediaController && supportsSeeking();
+}
+
 bool HTMLMediaElement::loop() const
 {
     return hasAttributeWithoutSynchronization(loopAttr);
@@ -4851,7 +4867,7 @@
     // When the current playback position reaches the end of the media resource then the user agent must follow these steps:
     if (dur && dur.isValid() && !dur.isPositiveInfinite() && !dur.isNegativeInfinite()) {
         // If the media element has a loop attribute specified and does not have a current media controller,
-        if (loop() && !m_mediaController && playbackRate > 0) {
+        if (loop() && playbackRate > 0 && canLoop()) {
             m_sentEndEvent = false;
             // then seek to the earliest possible position of the media resource and abort these steps when the direction of
             // playback is forwards,
@@ -4882,7 +4898,7 @@
             m_sentEndEvent = false;
     } else {
 #if ENABLE(MEDIA_STREAM)
-        if (m_mediaStreamSrcObject) {
+        if (hasMediaStreamSrcObject()) {
             // http://w3c.github.io/mediacapture-main/#event-mediastream-inactive
             // 6. MediaStreams in Media Elements
             // When the MediaStream state moves from the active to the inactive state, the User Agent
@@ -5606,8 +5622,7 @@
 void HTMLMediaElement::clearMediaPlayer()
 {
 #if ENABLE(MEDIA_STREAM)
-    if (!m_settingMediaStreamSrcObject)
-        m_mediaStreamSrcObject = nullptr;
+    m_mediaStreamSrcObject = nullptr;
 #endif
 
 #if ENABLE(MEDIA_SOURCE)
diff --git a/Source/WebCore/html/HTMLMediaElement.h b/Source/WebCore/html/HTMLMediaElement.h
index 12d107f..13f47e2 100644
--- a/Source/WebCore/html/HTMLMediaElement.h
+++ b/Source/WebCore/html/HTMLMediaElement.h
@@ -958,6 +958,8 @@
 
     void setInActiveDocument(bool);
 
+    bool canLoop() const;
+
 #if !RELEASE_LOG_DISABLED
     const void* mediaPlayerLogIdentifier() final { return logIdentifier(); }
     const Logger& mediaPlayerLogger() final { return logger(); }
@@ -1210,7 +1212,6 @@
 
 #if ENABLE(MEDIA_STREAM)
     RefPtr<MediaStream> m_mediaStreamSrcObject;
-    bool m_settingMediaStreamSrcObject { false };
 #endif
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
diff --git a/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h b/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h
index 740e96c..62fa706 100644
--- a/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h
+++ b/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h
@@ -240,6 +240,7 @@
     std::unique_ptr<PAL::Clock> m_clock;
 
     MediaTime m_pausedTime;
+    mutable MediaTime m_lastReportedTime;
 
     struct CurrentFramePainter {
         CurrentFramePainter() = default;
diff --git a/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm b/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm
index 6314814..283183a 100644
--- a/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm
+++ b/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm
@@ -741,15 +741,23 @@
 
 MediaTime MediaPlayerPrivateMediaStreamAVFObjC::durationMediaTime() const
 {
+    if (m_ended)
+        return m_lastReportedTime;
+
     return MediaTime::positiveInfiniteTime();
 }
 
 MediaTime MediaPlayerPrivateMediaStreamAVFObjC::currentMediaTime() const
 {
-    if (paused())
-        return m_pausedTime;
+    if (m_ended)
+        return m_lastReportedTime;
 
-    return streamTime();
+    if (paused())
+        m_lastReportedTime = m_pausedTime;
+    else
+        m_lastReportedTime = streamTime();
+
+    return m_lastReportedTime;
 }
 
 MediaTime MediaPlayerPrivateMediaStreamAVFObjC::streamTime() const
@@ -769,9 +777,12 @@
 
 MediaPlayer::ReadyState MediaPlayerPrivateMediaStreamAVFObjC::currentReadyState()
 {
-    if (!m_mediaStreamPrivate || !m_mediaStreamPrivate->active() || !m_mediaStreamPrivate->tracks().size())
+    if (!m_mediaStreamPrivate || !m_mediaStreamPrivate->tracks().size())
         return MediaPlayer::ReadyState::HaveNothing;
 
+    if (m_ended || m_waitingForFirstImage)
+        return MediaPlayer::ReadyState::HaveMetadata;
+
     bool allTracksAreLive = true;
     for (auto& track : m_mediaStreamPrivate->tracks()) {
         if (!track->enabled() || track->readyState() != MediaStreamTrackPrivate::ReadyState::Live)
@@ -784,7 +795,7 @@
         }
     }
 
-    if (m_waitingForFirstImage || (!allTracksAreLive && !m_haveSeenMetadata))
+    if (!allTracksAreLive && !m_haveSeenMetadata)
         return MediaPlayer::ReadyState::HaveMetadata;
 
     return MediaPlayer::ReadyState::HaveEnoughData;
@@ -815,6 +826,8 @@
             if (m_player) {
                 m_player->timeChanged();
                 m_player->characteristicChanged();
+                if (m_ended)
+                    m_player->durationChanged();
             }
         }
     });