Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: a243dd0c442e7b4cdd6e5d854116281599c6bafc
https://github.com/WebKit/WebKit/commit/a243dd0c442e7b4cdd6e5d854116281599c6bafc
Author: Jean-Yves Avenard <[email protected]>
Date: 2026-05-17 (Sun, 17 May 2026)
Changed paths:
M
LayoutTests/imported/w3c/web-platform-tests/media-source/mediasource-duration-expected.txt
M
LayoutTests/imported/w3c/web-platform-tests/media-source/mediasource-duration.html
M LayoutTests/platform/mac/TestExpectations
M Source/WebCore/Modules/mediasource/MediaSource.cpp
M Source/WebCore/platform/graphics/avfoundation/AudioVideoRendererAVFObjC.mm
M
Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h
M
Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm
Log Message:
-----------
[MSE] mediasource-duration WPT test fails on multi-track content
https://bugs.webkit.org/show_bug.cgi?id=222422
rdar://176599938
Reviewed by Eric Carlson.
Several independent bugs along the duration-truncation seek path caused
the mediasource-duration WPT test to fail on multi-track mp4 content:
1. MediaSource::setDurationInternal lost MediaTime precision when the
JS-supplied duration equalled the highest buffered end time. The JS
Number arrives as a MediaTime constructed via createWithDouble (the
"DoubleValue" form, which holds a raw double). The spec normalisation
step 4 only swaps to the precise rational highestEndTime when
newDuration is *strictly less* than it; on equality the imprecise
DoubleValue won, then propagated through durationChanged ->
mediaPlayerDurationChanged -> seekInternal as the seek target.
Eventually SourceBufferPrivate::computeSeekTime saw a DoubleValue
target and rounded it to MediaTime::DefaultTimeScale (10M), losing
precision. Use <= so that the precise rational from the buffered
ranges is picked on equality, and the precise value flows through to
computeSeekTime where the DoubleValue branch is skipped entirely.
2. AudioVideoRendererAVFObjC::notifyTimeReachedAndStall's boundary
observer callback fired the WebContent-side callback with `now`
(currentTime() captured before re-pinning the synchronizer), even
though it then re-set the synchronizer to the precise timeBoundary
immediately after. The reported time therefore carried the
synchronizer's timescale-rounded value rather than the precise
requested value. Fire callback(timeBoundary) so the value matches
what the synchronizer was just pinned to.
3. The same boundary observer also called pause() and timeChanged()
unconditionally. During an in-flight seek (e.g. the seek triggered by
a duration truncation), pausing mid-seek and firing timeChanged()
races with the seek's own state transitions and produces
spec-incorrect event ordering (timeupdate before seeking). Skip both
calls when seeking() is true and let the seek path drive state
transitions.
4. The "setting same duration multiple times does not fire duplicate
durationchange" subtest timed out ~60% of the time in WebKitTestRunner
because the 'ended' event was never scheduled. Log-traced cause: after
endOfStream() the boundary observer is programmed at
stallAtTime = highestEndTime (audio-sample-aligned, longer than the
video-frame-aligned end). Playback drains naturally - currentTime
advances to exactly highestEndTime and stops - but
AVSampleBufferRenderSynchronizer's boundary-time observer does not
fire in that case. The effectiveRate-changed listener, however, does
fire when the synchronizer rate drops to 0 at drain. Use that as a
reliable signal: in MediaPlayerPrivateMediaSourceAVFObjC::
effectiveRateChanged(), when effectiveRate == 0 and MediaSource is
in the 'ended' state and MediaSourcePrivate::hasFutureTime(currentTime)
is false, route a timeChanged() through so
HTMLMediaElement::mediaPlayerTimeChanged schedules the 'ended' event
(currentTime == duration at this point, satisfying its now >= dur
check). The existing 'if (!effectiveRate()) timeChanged()' fallback
in mediaSourceHasRetrievedAllData() is replaced with the same helper
for consistency; the isEnded() gate is always true in that context
(the caller sets m_ended = true before dispatching), making the gate
explicit and symmetric with the effectiveRateChanged site.
*
LayoutTests/imported/w3c/web-platform-tests/media-source/mediasource-duration-expected.txt:
Three subtests now pass.
*
LayoutTests/imported/w3c/web-platform-tests/media-source/mediasource-duration.html:
The last test was invalid.
It adds data from 0.095 and expect the mediaElement's play promise to be
resolved ; it can't be as with this starting
gap there's nothing to play. Remove the call to play() it's not required for
this test.
* LayoutTests/platform/mac/TestExpectations: Drop the flaky/Failure
expectation that covered these failures.
* Source/WebCore/Modules/mediasource/MediaSource.cpp:
(WebCore::MediaSource::setDurationInternal):
* Source/WebCore/platform/graphics/avfoundation/AudioVideoRendererAVFObjC.mm:
(WebCore::AudioVideoRendererAVFObjC::notifyTimeReachedAndStall):
*
Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h:
*
Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::bufferedChanged):
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::effectiveRateChanged):
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::notifyEndOfMediaIfNeeded):
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::mediaSourceHasRetrievedAllData):
Canonical link: https://commits.webkit.org/313385@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications