Diff
Modified: trunk/Source/WebCore/ChangeLog (279042 => 279043)
--- trunk/Source/WebCore/ChangeLog 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebCore/ChangeLog 2021-06-18 19:15:40 UTC (rev 279043)
@@ -1,3 +1,57 @@
+2021-06-18 Peng Liu <[email protected]>
+
+ [iOS] Fullscreen video playback gets stuck after interacting with the playback controls
+ https://bugs.webkit.org/show_bug.cgi?id=227047
+
+ Reviewed by Eric Carlson.
+
+ When we scrub a playing video, the video element may enter a temporarily stalled
+ state - the player is still playing, but it does not have enough data. In WebKit,
+ the `rate` of the player will be 0. But we cannot set the rate of `WebAVPlayerController`
+ to 0 in this case, because AVKit will believe the video playback is paused when
+ its rate is 0. In r261587, we defined a magic rate (0.00000001f) for this case.
+
+ Unfortunately, with the changes in r275956, `WebAVPlayerController` will
+ align its `defaultPlaybackRate` with `rate` when `rate` is not 0. Under stress
+ tests, e.g., keep scrubbing a video, a video element will eventually enter a state
+ in which both `defaultPlaybackRate` and `rate` are the magic rate. And the video
+ appears to be stuck for users.
+
+ To fix the issue, this patch removes the magic rate and defines a new state: `stalled`.
+ A video will be in the stalled state when it is playing but does not have enough data.
+ WebKit will only change the rate of `WebAVPlayerController` when the video
+ is not stalled.
+
+ To avoid potential problems due to the conversions between "float" and "double"
+ back and forth, this patch updates the types of `playbackRate` and `defaultPlaybackRate`.
+
+ * platform/cocoa/PlaybackSessionModel.h:
+ (WebCore::PlaybackSessionModelClient::rateChanged):
+ * platform/cocoa/PlaybackSessionModelMediaElement.h:
+ * platform/cocoa/PlaybackSessionModelMediaElement.mm:
+ (WebCore::PlaybackSessionModelMediaElement::updateForEventName):
+ (WebCore::PlaybackSessionModelMediaElement::setDefaultPlaybackRate):
+ (WebCore::PlaybackSessionModelMediaElement::setPlaybackRate):
+ (WebCore::PlaybackSessionModelMediaElement::defaultPlaybackRate const):
+ (WebCore::PlaybackSessionModelMediaElement::playbackRate const):
+ * platform/ios/PlaybackSessionInterfaceAVKit.h:
+ * platform/ios/PlaybackSessionInterfaceAVKit.mm:
+ (WebCore::PlaybackSessionInterfaceAVKit::PlaybackSessionInterfaceAVKit):
+ (WebCore::PlaybackSessionInterfaceAVKit::rateChanged):
+ * platform/ios/WebVideoFullscreenControllerAVKit.mm:
+ (VideoFullscreenControllerContext::rateChanged):
+ (VideoFullscreenControllerContext::setDefaultPlaybackRate):
+ (VideoFullscreenControllerContext::setPlaybackRate):
+ (VideoFullscreenControllerContext::isStalled const):
+ (VideoFullscreenControllerContext::defaultPlaybackRate const):
+ (VideoFullscreenControllerContext::playbackRate const):
+ * platform/mac/PlaybackSessionInterfaceMac.h:
+ * platform/mac/PlaybackSessionInterfaceMac.mm:
+ (WebCore::PlaybackSessionInterfaceMac::rateChanged):
+ * platform/mac/VideoFullscreenInterfaceMac.h:
+ * platform/mac/VideoFullscreenInterfaceMac.mm:
+ (WebCore::VideoFullscreenInterfaceMac::rateChanged):
+
2021-06-18 Philippe Normand <[email protected]>
[MSE][GStreamer] Soundcloud serves MP4 audio with empty tfdt boxes
Modified: trunk/Source/WebCore/platform/cocoa/PlaybackSessionModel.h (279042 => 279043)
--- trunk/Source/WebCore/platform/cocoa/PlaybackSessionModel.h 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebCore/platform/cocoa/PlaybackSessionModel.h 2021-06-18 19:15:40 UTC (rev 279043)
@@ -55,8 +55,8 @@
virtual void beginScanningForward() = 0;
virtual void beginScanningBackward() = 0;
virtual void endScanning() = 0;
- virtual void setDefaultPlaybackRate(float) = 0;
- virtual void setPlaybackRate(float) = 0;
+ virtual void setDefaultPlaybackRate(double) = 0;
+ virtual void setPlaybackRate(double) = 0;
virtual void selectAudioMediaOption(uint64_t index) = 0;
virtual void selectLegibleMediaOption(uint64_t index) = 0;
virtual void togglePictureInPicture() = 0;
@@ -72,10 +72,16 @@
virtual double duration() const = 0;
virtual double currentTime() const = 0;
virtual double bufferedTime() const = 0;
+
+ enum class PlaybackState {
+ Playing = 1 << 0,
+ Stalled = 1 << 1,
+ };
virtual bool isPlaying() const = 0;
+ virtual bool isStalled() const = 0;
virtual bool isScrubbing() const = 0;
- virtual float defaultPlaybackRate() const = 0;
- virtual float playbackRate() const = 0;
+ virtual double defaultPlaybackRate() const = 0;
+ virtual double playbackRate() const = 0;
virtual Ref<TimeRanges> seekableRanges() const = 0;
virtual double seekableTimeRangesLastModifiedTime() const = 0;
virtual double liveUpdateInterval() const = 0;
@@ -101,7 +107,7 @@
virtual void currentTimeChanged(double /* currentTime */, double /* anchorTime */) { }
virtual void bufferedTimeChanged(double) { }
virtual void playbackStartedTimeChanged(double /* playbackStartedTime */) { }
- virtual void rateChanged(bool /* isPlaying */, float /* playbackRate */, float /* defaultPlaybackRate */) { }
+ virtual void rateChanged(OptionSet<PlaybackSessionModel::PlaybackState>, double /* playbackRate */, double /* defaultPlaybackRate */) { }
virtual void seekableRangesChanged(const TimeRanges&, double /* lastModified */, double /* liveInterval */) { }
virtual void canPlayFastReverseChanged(bool) { }
virtual void audioMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& /* options */, uint64_t /* selectedIndex */) { }
@@ -118,6 +124,18 @@
virtual void modelDestroyed() { }
};
-}
+} // namespace WebCore
+namespace WTF {
+
+template<> struct EnumTraits<WebCore::PlaybackSessionModel::PlaybackState> {
+ using values = EnumValues<
+ WebCore::PlaybackSessionModel::PlaybackState,
+ WebCore::PlaybackSessionModel::PlaybackState::Playing,
+ WebCore::PlaybackSessionModel::PlaybackState::Stalled
+ >;
+};
+
+} // namespace WTF
+
#endif // PLATFORM(IOS_FAMILY) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
Modified: trunk/Source/WebCore/platform/cocoa/PlaybackSessionModelMediaElement.h (279042 => 279043)
--- trunk/Source/WebCore/platform/cocoa/PlaybackSessionModelMediaElement.h 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebCore/platform/cocoa/PlaybackSessionModelMediaElement.h 2021-06-18 19:15:40 UTC (rev 279043)
@@ -68,8 +68,8 @@
WEBCORE_EXPORT void beginScanningForward() final;
WEBCORE_EXPORT void beginScanningBackward() final;
WEBCORE_EXPORT void endScanning() final;
- WEBCORE_EXPORT void setDefaultPlaybackRate(float) final;
- WEBCORE_EXPORT void setPlaybackRate(float) final;
+ WEBCORE_EXPORT void setDefaultPlaybackRate(double) final;
+ WEBCORE_EXPORT void setPlaybackRate(double) final;
WEBCORE_EXPORT void selectAudioMediaOption(uint64_t index) final;
WEBCORE_EXPORT void selectLegibleMediaOption(uint64_t index) final;
WEBCORE_EXPORT void togglePictureInPicture() final;
@@ -83,9 +83,10 @@
double currentTime() const final;
double bufferedTime() const final;
bool isPlaying() const final;
+ bool isStalled() const final;
bool isScrubbing() const final { return false; }
- float defaultPlaybackRate() const final;
- float playbackRate() const final;
+ double defaultPlaybackRate() const final;
+ double playbackRate() const final;
Ref<TimeRanges> seekableRanges() const final;
double seekableTimeRangesLastModifiedTime() const final;
double liveUpdateInterval() const final;
@@ -109,7 +110,6 @@
void progressEventTimerFired();
static const Vector<WTF::AtomString>& observedEventNames();
const WTF::AtomString& eventNameAll();
- bool isStalled() const;
RefPtr<HTMLMediaElement> m_mediaElement;
bool m_isListening { false };
Modified: trunk/Source/WebCore/platform/cocoa/PlaybackSessionModelMediaElement.mm (279042 => 279043)
--- trunk/Source/WebCore/platform/cocoa/PlaybackSessionModelMediaElement.mm 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebCore/platform/cocoa/PlaybackSessionModelMediaElement.mm 2021-06-18 19:15:40 UTC (rev 279043)
@@ -47,13 +47,6 @@
namespace WebCore {
-// This is the rate which we report to our clients, namely AVKit, when playback has stalled.
-// The value must be non-zero, so as to differentiate "playing-but-stalled" from "paused". But
-// the value also must be very small, so there is no visible movement in the system provided
-// timeline slider when stalled. The value below will cause the slider to move 1 second every
-// 3 years, so meets both goals.
-static const float StalledPlaybackRate = 0.00000001f;
-
PlaybackSessionModelMediaElement::PlaybackSessionModelMediaElement()
: EventListener(EventListener::CPPEventListenerType)
{
@@ -162,11 +155,16 @@
|| eventName == eventNames().ratechangeEvent
|| eventName == eventNames().waitingEvent
|| eventName == eventNames().canplayEvent) {
- bool isPlaying = this->isPlaying();
- float playbackRate = isStalled() ? StalledPlaybackRate : this->playbackRate();
- float defaultPlaybackRate = this->defaultPlaybackRate();
+ OptionSet<PlaybackSessionModel::PlaybackState> playbackState;
+ if (isPlaying())
+ playbackState.add(PlaybackSessionModel::PlaybackState::Playing);
+ if (isStalled())
+ playbackState.add(PlaybackSessionModel::PlaybackState::Stalled);
+
+ double playbackRate = this->playbackRate();
+ double defaultPlaybackRate = this->defaultPlaybackRate();
for (auto client : m_clients)
- client->rateChanged(isPlaying, playbackRate, defaultPlaybackRate);
+ client->rateChanged(playbackState, playbackRate, defaultPlaybackRate);
}
if (all
@@ -302,13 +300,13 @@
m_mediaElement->endScanning();
}
-void PlaybackSessionModelMediaElement::setDefaultPlaybackRate(float defaultPlaybackRate)
+void PlaybackSessionModelMediaElement::setDefaultPlaybackRate(double defaultPlaybackRate)
{
if (m_mediaElement)
m_mediaElement->setDefaultPlaybackRate(defaultPlaybackRate);
}
-void PlaybackSessionModelMediaElement::setPlaybackRate(float playbackRate)
+void PlaybackSessionModelMediaElement::setPlaybackRate(double playbackRate)
{
if (m_mediaElement)
m_mediaElement->setPlaybackRate(playbackRate);
@@ -481,12 +479,12 @@
return m_mediaElement && m_mediaElement->readyState() <= HTMLMediaElement::HAVE_CURRENT_DATA;
}
-float PlaybackSessionModelMediaElement::defaultPlaybackRate() const
+double PlaybackSessionModelMediaElement::defaultPlaybackRate() const
{
return m_mediaElement ? m_mediaElement->defaultPlaybackRate() : 0;
}
-float PlaybackSessionModelMediaElement::playbackRate() const
+double PlaybackSessionModelMediaElement::playbackRate() const
{
return m_mediaElement ? m_mediaElement->playbackRate() : 0;
}
Modified: trunk/Source/WebCore/platform/ios/PlaybackSessionInterfaceAVKit.h (279042 => 279043)
--- trunk/Source/WebCore/platform/ios/PlaybackSessionInterfaceAVKit.h 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebCore/platform/ios/PlaybackSessionInterfaceAVKit.h 2021-06-18 19:15:40 UTC (rev 279043)
@@ -63,7 +63,7 @@
void durationChanged(double) override;
void currentTimeChanged(double currentTime, double anchorTime) override;
void bufferedTimeChanged(double) override;
- void rateChanged(bool isPlaying, float playbackRate, float defaultPlaybackRate) override;
+ void rateChanged(OptionSet<PlaybackSessionModel::PlaybackState>, double playbackRate, double defaultPlaybackRate) override;
void seekableRangesChanged(const TimeRanges&, double lastModifiedTime, double liveUpdateInterval) override;
void canPlayFastReverseChanged(bool) override;
void audioMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex) override;
Modified: trunk/Source/WebCore/platform/ios/PlaybackSessionInterfaceAVKit.mm (279042 => 279043)
--- trunk/Source/WebCore/platform/ios/PlaybackSessionInterfaceAVKit.mm 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebCore/platform/ios/PlaybackSessionInterfaceAVKit.mm 2021-06-18 19:15:40 UTC (rev 279043)
@@ -61,7 +61,12 @@
durationChanged(model.duration());
currentTimeChanged(model.currentTime(), [[NSProcessInfo processInfo] systemUptime]);
bufferedTimeChanged(model.bufferedTime());
- rateChanged(model.isPlaying(), model.playbackRate(), model.defaultPlaybackRate());
+ OptionSet<PlaybackSessionModel::PlaybackState> playbackState;
+ if (model.isPlaying())
+ playbackState.add(PlaybackSessionModel::PlaybackState::Playing);
+ if (model.isStalled())
+ playbackState.add(PlaybackSessionModel::PlaybackState::Stalled);
+ rateChanged(playbackState, model.playbackRate(), model.defaultPlaybackRate());
seekableRangesChanged(model.seekableRanges(), model.seekableTimeRangesLastModifiedTime(), model.liveUpdateInterval());
canPlayFastReverseChanged(model.canPlayFastReverse());
audioMediaSelectionOptionsChanged(model.audioMediaSelectionOptions(), model.audioMediaSelectedIndex());
@@ -124,10 +129,11 @@
playerController.loadedTimeRanges = @[@0, @(normalizedBufferedTime)];
}
-void PlaybackSessionInterfaceAVKit::rateChanged(bool isPlaying, float playbackRate, float defaultPlaybackRate)
+void PlaybackSessionInterfaceAVKit::rateChanged(OptionSet<PlaybackSessionModel::PlaybackState> playbackState, double playbackRate, double defaultPlaybackRate)
{
[m_playerController setDefaultPlaybackRate:defaultPlaybackRate];
- [m_playerController setRate:isPlaying ? playbackRate : 0.];
+ if (!playbackState.contains(PlaybackSessionModel::PlaybackState::Stalled))
+ [m_playerController setRate:playbackState.contains(PlaybackSessionModel::PlaybackState::Playing) ? playbackRate : 0.];
}
void PlaybackSessionInterfaceAVKit::seekableRangesChanged(const TimeRanges& timeRanges, double lastModifiedTime, double liveUpdateInterval)
Modified: trunk/Source/WebCore/platform/ios/WebVideoFullscreenControllerAVKit.mm (279042 => 279043)
--- trunk/Source/WebCore/platform/ios/WebVideoFullscreenControllerAVKit.mm 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebCore/platform/ios/WebVideoFullscreenControllerAVKit.mm 2021-06-18 19:15:40 UTC (rev 279043)
@@ -149,8 +149,8 @@
void beginScanningForward() override;
void beginScanningBackward() override;
void endScanning() override;
- void setDefaultPlaybackRate(float) override;
- void setPlaybackRate(float) override;
+ void setDefaultPlaybackRate(double) override;
+ void setPlaybackRate(double) override;
void selectAudioMediaOption(uint64_t) override;
void selectLegibleMediaOption(uint64_t) override;
double duration() const override;
@@ -158,9 +158,10 @@
double currentTime() const override;
double bufferedTime() const override;
bool isPlaying() const override;
+ bool isStalled() const override;
bool isScrubbing() const override { return false; }
- float defaultPlaybackRate() const override;
- float playbackRate() const override;
+ double defaultPlaybackRate() const override;
+ double playbackRate() const override;
Ref<TimeRanges> seekableRanges() const override;
double seekableTimeRangesLastModifiedTime() const override;
double liveUpdateInterval() const override;
@@ -183,7 +184,7 @@
void durationChanged(double) override;
void currentTimeChanged(double currentTime, double anchorTime) override;
void bufferedTimeChanged(double) override;
- void rateChanged(bool isPlaying, float playbackRate, float defaultPlaybackRate) override;
+ void rateChanged(OptionSet<PlaybackSessionModel::PlaybackState>, double playbackRate, double defaultPlaybackRate) override;
void seekableRangesChanged(const TimeRanges&, double lastModifiedTime, double liveUpdateInterval) override;
void canPlayFastReverseChanged(bool) override;
void audioMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex) override;
@@ -416,17 +417,17 @@
client->bufferedTimeChanged(bufferedTime);
}
-void VideoFullscreenControllerContext::rateChanged(bool isPlaying, float playbackRate, float defaultPlaybackRate)
+void VideoFullscreenControllerContext::rateChanged(OptionSet<PlaybackSessionModel::PlaybackState> playbackState, double playbackRate, double defaultPlaybackRate)
{
if (WebThreadIsCurrent()) {
- RunLoop::main().dispatch([protectedThis = makeRefPtr(this), isPlaying, playbackRate, defaultPlaybackRate] {
- protectedThis->rateChanged(isPlaying, playbackRate, defaultPlaybackRate);
+ RunLoop::main().dispatch([protectedThis = makeRefPtr(this), playbackState, playbackRate, defaultPlaybackRate] {
+ protectedThis->rateChanged(playbackState, playbackRate, defaultPlaybackRate);
});
return;
}
for (auto& client : m_playbackClients)
- client->rateChanged(isPlaying, playbackRate, defaultPlaybackRate);
+ client->rateChanged(playbackState, playbackRate, defaultPlaybackRate);
}
void VideoFullscreenControllerContext::hasVideoChanged(bool hasVideo)
@@ -841,7 +842,7 @@
});
}
-void VideoFullscreenControllerContext::setDefaultPlaybackRate(float defaultPlaybackRate)
+void VideoFullscreenControllerContext::setDefaultPlaybackRate(double defaultPlaybackRate)
{
ASSERT(isUIThread());
WebThreadRun([protectedThis = makeRefPtr(this), this, defaultPlaybackRate] {
@@ -850,7 +851,7 @@
});
}
-void VideoFullscreenControllerContext::setPlaybackRate(float playbackRate)
+void VideoFullscreenControllerContext::setPlaybackRate(double playbackRate)
{
ASSERT(isUIThread());
WebThreadRun([protectedThis = makeRefPtr(this), this, playbackRate] {
@@ -901,13 +902,19 @@
return m_playbackModel ? m_playbackModel->isPlaying() : false;
}
-float VideoFullscreenControllerContext::defaultPlaybackRate() const
+bool VideoFullscreenControllerContext::isStalled() const
{
ASSERT(isUIThread());
+ return m_playbackModel ? m_playbackModel->isStalled() : false;
+}
+
+double VideoFullscreenControllerContext::defaultPlaybackRate() const
+{
+ ASSERT(isUIThread());
return m_playbackModel ? m_playbackModel->defaultPlaybackRate() : 0;
}
-float VideoFullscreenControllerContext::playbackRate() const
+double VideoFullscreenControllerContext::playbackRate() const
{
ASSERT(isUIThread());
return m_playbackModel ? m_playbackModel->playbackRate() : 0;
Modified: trunk/Source/WebCore/platform/mac/PlaybackSessionInterfaceMac.h (279042 => 279043)
--- trunk/Source/WebCore/platform/mac/PlaybackSessionInterfaceMac.h 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebCore/platform/mac/PlaybackSessionInterfaceMac.h 2021-06-18 19:15:40 UTC (rev 279043)
@@ -52,7 +52,7 @@
// PlaybackSessionModelClient
void durationChanged(double) final;
void currentTimeChanged(double /*currentTime*/, double /*anchorTime*/) final;
- void rateChanged(bool /*isPlaying*/, float /*playbackRate*/, float /* defaultPlaybackRate */) final;
+ void rateChanged(OptionSet<PlaybackSessionModel::PlaybackState>, double /* playbackRate */, double /* defaultPlaybackRate */) final;
void seekableRangesChanged(const TimeRanges&, double /*lastModifiedTime*/, double /*liveUpdateInterval*/) final;
void audioMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& /*options*/, uint64_t /*selectedIndex*/) final;
void legibleMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& /*options*/, uint64_t /*selectedIndex*/) final;
Modified: trunk/Source/WebCore/platform/mac/PlaybackSessionInterfaceMac.mm (279042 => 279043)
--- trunk/Source/WebCore/platform/mac/PlaybackSessionInterfaceMac.mm 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebCore/platform/mac/PlaybackSessionInterfaceMac.mm 2021-06-18 19:15:40 UTC (rev 279043)
@@ -92,9 +92,10 @@
#endif
}
-void PlaybackSessionInterfaceMac::rateChanged(bool isPlaying, float playbackRate, float defaultPlaybackRate)
+void PlaybackSessionInterfaceMac::rateChanged(OptionSet<PlaybackSessionModel::PlaybackState> playbackState, double playbackRate, double defaultPlaybackRate)
{
#if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
+ auto isPlaying = playbackState.contains(PlaybackSessionModel::PlaybackState::Playing);
WebPlaybackControlsManager* controlsManager = playBackControlsManager();
[controlsManager setRate:isPlaying ? playbackRate : 0.];
[controlsManager setDefaultPlaybackRate:defaultPlaybackRate];
Modified: trunk/Source/WebCore/platform/mac/VideoFullscreenInterfaceMac.h (279042 => 279043)
--- trunk/Source/WebCore/platform/mac/VideoFullscreenInterfaceMac.h 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebCore/platform/mac/VideoFullscreenInterfaceMac.h 2021-06-18 19:15:40 UTC (rev 279043)
@@ -63,7 +63,7 @@
WEBCORE_EXPORT void setVideoFullscreenChangeObserver(VideoFullscreenChangeObserver*);
// PlaybackSessionModelClient
- WEBCORE_EXPORT void rateChanged(bool isPlaying, float playbackRate, float defaultPlaybackRate) override;
+ WEBCORE_EXPORT void rateChanged(OptionSet<PlaybackSessionModel::PlaybackState>, double playbackRate, double defaultPlaybackRate) override;
WEBCORE_EXPORT void externalPlaybackChanged(bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType, const String& localizedDeviceName) override;
WEBCORE_EXPORT void ensureControlsManager() override;
Modified: trunk/Source/WebCore/platform/mac/VideoFullscreenInterfaceMac.mm (279042 => 279043)
--- trunk/Source/WebCore/platform/mac/VideoFullscreenInterfaceMac.mm 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebCore/platform/mac/VideoFullscreenInterfaceMac.mm 2021-06-18 19:15:40 UTC (rev 279043)
@@ -428,9 +428,9 @@
m_videoFullscreenModel->fullscreenModeChanged(m_mode);
}
-void VideoFullscreenInterfaceMac::rateChanged(bool isPlaying, float playbackRate, float /* defaultPlaybackRate */)
+void VideoFullscreenInterfaceMac::rateChanged(OptionSet<PlaybackSessionModel::PlaybackState> playbackState, double playbackRate, double /* defaultPlaybackRate */)
{
- [videoFullscreenInterfaceObjC() updateIsPlaying:isPlaying newPlaybackRate:playbackRate];
+ [videoFullscreenInterfaceObjC() updateIsPlaying:playbackState.contains(PlaybackSessionModel::PlaybackState::Playing) newPlaybackRate:playbackRate];
}
void VideoFullscreenInterfaceMac::ensureControlsManager()
Modified: trunk/Source/WebKit/ChangeLog (279042 => 279043)
--- trunk/Source/WebKit/ChangeLog 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebKit/ChangeLog 2021-06-18 19:15:40 UTC (rev 279043)
@@ -1,3 +1,47 @@
+2021-06-18 Peng Liu <[email protected]>
+
+ [iOS] Fullscreen video playback gets stuck after interacting with the playback controls
+ https://bugs.webkit.org/show_bug.cgi?id=227047
+
+ Reviewed by Eric Carlson.
+
+ When we scrub a playing video, the video element may enter a temporarily stalled
+ state - the player is still playing, but it does not have enough data. In WebKit,
+ the `rate` of the player will be 0. But we cannot set the rate of `WebAVPlayerController`
+ to 0 in this case, because AVKit will believe the video playback is paused when
+ its rate is 0. In r261587, we defined a magic rate (0.00000001f) for this case.
+
+ Unfortunately, with the changes in r275956, `WebAVPlayerController` will
+ align its `defaultPlaybackRate` with `rate` when `rate` is not 0. Under stress
+ tests, e.g., keep scrubbing a video, a video element will eventually enter a state
+ in which both `defaultPlaybackRate` and `rate` are the magic rate. And the video
+ appears to be stuck for users.
+
+ To fix the issue, this patch removes the magic rate and defines a new state: `stalled`.
+ A video will be in the stalled state when it is playing but does not have enough data.
+ WebKit will only change the rate of `WebAVPlayerController` when the video
+ is not stalled.
+
+ To avoid potential problems due to the conversions between "float" and "double"
+ back and forth, this patch updates the types of `playbackRate` and `defaultPlaybackRate`.
+
+ * Scripts/webkit/messages.py:
+ (headers_for_type):
+ * UIProcess/Cocoa/PlaybackSessionManagerProxy.h:
+ * UIProcess/Cocoa/PlaybackSessionManagerProxy.messages.in:
+ * UIProcess/Cocoa/PlaybackSessionManagerProxy.mm:
+ (WebKit::PlaybackSessionModelContext::setDefaultPlaybackRate):
+ (WebKit::PlaybackSessionModelContext::setPlaybackRate):
+ (WebKit::PlaybackSessionModelContext::rateChanged):
+ (WebKit::PlaybackSessionManagerProxy::rateChanged):
+ (WebKit::PlaybackSessionManagerProxy::setDefaultPlaybackRate):
+ (WebKit::PlaybackSessionManagerProxy::setPlaybackRate):
+ * UIProcess/ios/fullscreen/WKFullScreenViewController.mm:
+ * WebProcess/cocoa/PlaybackSessionManager.h:
+ * WebProcess/cocoa/PlaybackSessionManager.mm:
+ (WebKit::PlaybackSessionInterfaceContext::rateChanged):
+ (WebKit::PlaybackSessionManager::rateChanged):
+
2021-06-18 Zan Dobersek <[email protected]>
[WPE] Rework touch-based gesture controller
Modified: trunk/Source/WebKit/Scripts/webkit/messages.py (279042 => 279043)
--- trunk/Source/WebKit/Scripts/webkit/messages.py 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebKit/Scripts/webkit/messages.py 2021-06-18 19:15:40 UTC (rev 279043)
@@ -715,6 +715,7 @@
'WebCore::PaymentAuthorizationResult': ['<WebCore/ApplePaySessionPaymentRequest.h>'],
'WebCore::PixelFormat': ['<WebCore/ImageBufferBackend.h>'],
'WebCore::PlatformTextTrackData': ['<WebCore/PlatformTextTrack.h>'],
+ 'WebCore::PlaybackSessionModel::PlaybackState': ['<WebCore/PlaybackSessionModel.h>'],
'WebCore::PluginInfo': ['<WebCore/PluginData.h>'],
'WebCore::PluginLoadClientPolicy': ['<WebCore/PluginData.h>'],
'WebCore::PolicyAction': ['<WebCore/FrameLoaderTypes.h>'],
Modified: trunk/Source/WebKit/UIProcess/Cocoa/PlaybackSessionManagerProxy.h (279042 => 279043)
--- trunk/Source/WebKit/UIProcess/Cocoa/PlaybackSessionManagerProxy.h 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebKit/UIProcess/Cocoa/PlaybackSessionManagerProxy.h 2021-06-18 19:15:40 UTC (rev 279043)
@@ -75,7 +75,7 @@
void currentTimeChanged(double);
void bufferedTimeChanged(double);
void playbackStartedTimeChanged(double);
- void rateChanged(bool isPlaying, float playbackRate, float defaultPlaybackRate);
+ void rateChanged(OptionSet<WebCore::PlaybackSessionModel::PlaybackState>, double playbackRate, double defaultPlaybackRate);
void seekableRangesChanged(WebCore::TimeRanges&, double lastModifiedTime, double liveUpdateInterval);
void canPlayFastReverseChanged(bool);
void audioMediaSelectionOptionsChanged(const Vector<WebCore::MediaSelectionOption>& options, uint64_t index);
@@ -111,8 +111,8 @@
void beginScanningForward() final;
void beginScanningBackward() final;
void endScanning() final;
- void setDefaultPlaybackRate(float) final;
- void setPlaybackRate(float) final;
+ void setDefaultPlaybackRate(double) final;
+ void setPlaybackRate(double) final;
void selectAudioMediaOption(uint64_t) final;
void selectLegibleMediaOption(uint64_t) final;
void togglePictureInPicture() final;
@@ -126,10 +126,11 @@
double duration() const final { return m_duration; }
double currentTime() const final { return m_currentTime; }
double bufferedTime() const final { return m_bufferedTime; }
- bool isPlaying() const final { return m_isPlaying; }
+ bool isPlaying() const final { return m_playbackState.contains(PlaybackState::Playing); }
+ bool isStalled() const final { return m_playbackState.contains(PlaybackState::Stalled); }
bool isScrubbing() const final { return m_isScrubbing; }
- float defaultPlaybackRate() const final { return m_defaultPlaybackRate; }
- float playbackRate() const final { return m_playbackRate; }
+ double defaultPlaybackRate() const final { return m_defaultPlaybackRate; }
+ double playbackRate() const final { return m_playbackRate; }
Ref<WebCore::TimeRanges> seekableRanges() const final { return m_seekableRanges.copyRef(); }
double seekableTimeRangesLastModifiedTime() const final { return m_seekableTimeRangesLastModifiedTime; }
double liveUpdateInterval() const { return m_liveUpdateInterval; }
@@ -154,10 +155,10 @@
double m_duration { 0 };
double m_currentTime { 0 };
double m_bufferedTime { 0 };
- bool m_isPlaying { false };
+ OptionSet<PlaybackSessionModel::PlaybackState> m_playbackState;
bool m_isScrubbing { false };
- float m_defaultPlaybackRate { 0 };
- float m_playbackRate { 0 };
+ double m_defaultPlaybackRate { 0 };
+ double m_playbackRate { 0 };
Ref<WebCore::TimeRanges> m_seekableRanges { WebCore::TimeRanges::create() };
double m_seekableTimeRangesLastModifiedTime { 0 };
double m_liveUpdateInterval { 0 };
@@ -221,7 +222,7 @@
void wirelessVideoPlaybackDisabledChanged(PlaybackSessionContextIdentifier, bool);
void durationChanged(PlaybackSessionContextIdentifier, double duration);
void playbackStartedTimeChanged(PlaybackSessionContextIdentifier, double playbackStartedTime);
- void rateChanged(PlaybackSessionContextIdentifier, bool isPlaying, double rate, double defaultPlaybackRate);
+ void rateChanged(PlaybackSessionContextIdentifier, OptionSet<WebCore::PlaybackSessionModel::PlaybackState>, double rate, double defaultPlaybackRate);
void handleControlledElementIDResponse(PlaybackSessionContextIdentifier, String) const;
void mutedChanged(PlaybackSessionContextIdentifier, bool muted);
void volumeChanged(PlaybackSessionContextIdentifier, double volume);
@@ -238,8 +239,8 @@
void beginScanningForward(PlaybackSessionContextIdentifier);
void beginScanningBackward(PlaybackSessionContextIdentifier);
void endScanning(PlaybackSessionContextIdentifier);
- void setDefaultPlaybackRate(PlaybackSessionContextIdentifier, float);
- void setPlaybackRate(PlaybackSessionContextIdentifier, float);
+ void setDefaultPlaybackRate(PlaybackSessionContextIdentifier, double);
+ void setPlaybackRate(PlaybackSessionContextIdentifier, double);
void selectAudioMediaOption(PlaybackSessionContextIdentifier, uint64_t index);
void selectLegibleMediaOption(PlaybackSessionContextIdentifier, uint64_t index);
void togglePictureInPicture(PlaybackSessionContextIdentifier);
Modified: trunk/Source/WebKit/UIProcess/Cocoa/PlaybackSessionManagerProxy.messages.in (279042 => 279043)
--- trunk/Source/WebKit/UIProcess/Cocoa/PlaybackSessionManagerProxy.messages.in 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebKit/UIProcess/Cocoa/PlaybackSessionManagerProxy.messages.in 2021-06-18 19:15:40 UTC (rev 279043)
@@ -34,7 +34,7 @@
WirelessVideoPlaybackDisabledChanged(WebKit::PlaybackSessionContextIdentifier contextId, bool disabled)
DurationChanged(WebKit::PlaybackSessionContextIdentifier contextId, double duration)
PlaybackStartedTimeChanged(WebKit::PlaybackSessionContextIdentifier contextId, double playbackStartedTime)
- RateChanged(WebKit::PlaybackSessionContextIdentifier contextId, bool isPlaying, double rate, double defaultPlaybackRate)
+ RateChanged(WebKit::PlaybackSessionContextIdentifier contextId, OptionSet<WebCore::PlaybackSessionModel::PlaybackState> playbackState, double rate, double defaultPlaybackRate)
MutedChanged(WebKit::PlaybackSessionContextIdentifier contextId, bool muted);
VolumeChanged(WebKit::PlaybackSessionContextIdentifier contextId, double volume);
PictureInPictureSupportedChanged(WebKit::PlaybackSessionContextIdentifier contextId, bool pictureInPictureSupported)
Modified: trunk/Source/WebKit/UIProcess/Cocoa/PlaybackSessionManagerProxy.mm (279042 => 279043)
--- trunk/Source/WebKit/UIProcess/Cocoa/PlaybackSessionManagerProxy.mm 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebKit/UIProcess/Cocoa/PlaybackSessionManagerProxy.mm 2021-06-18 19:15:40 UTC (rev 279043)
@@ -121,13 +121,13 @@
m_manager->endScanning(m_contextId);
}
-void PlaybackSessionModelContext::setDefaultPlaybackRate(float defaultPlaybackRate)
+void PlaybackSessionModelContext::setDefaultPlaybackRate(double defaultPlaybackRate)
{
if (m_manager)
m_manager->setDefaultPlaybackRate(m_contextId, defaultPlaybackRate);
}
-void PlaybackSessionModelContext::setPlaybackRate(float playbackRate)
+void PlaybackSessionModelContext::setPlaybackRate(double playbackRate)
{
if (m_manager)
m_manager->setPlaybackRate(m_contextId, playbackRate);
@@ -206,13 +206,13 @@
client->bufferedTimeChanged(bufferedTime);
}
-void PlaybackSessionModelContext::rateChanged(bool isPlaying, float playbackRate, float defaultPlaybackRate)
+void PlaybackSessionModelContext::rateChanged(OptionSet<WebCore::PlaybackSessionModel::PlaybackState> playbackState, double playbackRate, double defaultPlaybackRate)
{
- m_isPlaying = isPlaying;
+ m_playbackState = playbackState;
m_playbackRate = playbackRate;
m_defaultPlaybackRate = defaultPlaybackRate;
for (auto* client : m_clients)
- client->rateChanged(m_isPlaying, m_playbackRate, m_defaultPlaybackRate);
+ client->rateChanged(m_playbackState, m_playbackRate, m_defaultPlaybackRate);
}
void PlaybackSessionModelContext::seekableRangesChanged(WebCore::TimeRanges& seekableRanges, double lastModifiedTime, double liveUpdateInterval)
@@ -489,9 +489,9 @@
ensureModel(contextId).playbackStartedTimeChanged(playbackStartedTime);
}
-void PlaybackSessionManagerProxy::rateChanged(PlaybackSessionContextIdentifier contextId, bool isPlaying, double rate, double defaultPlaybackRate)
+void PlaybackSessionManagerProxy::rateChanged(PlaybackSessionContextIdentifier contextId, OptionSet<WebCore::PlaybackSessionModel::PlaybackState> playbackState, double rate, double defaultPlaybackRate)
{
- ensureModel(contextId).rateChanged(isPlaying, rate, defaultPlaybackRate);
+ ensureModel(contextId).rateChanged(playbackState, rate, defaultPlaybackRate);
}
void PlaybackSessionManagerProxy::pictureInPictureSupportedChanged(PlaybackSessionContextIdentifier contextId, bool supported)
@@ -563,12 +563,12 @@
m_page->send(Messages::PlaybackSessionManager::EndScanning(contextId));
}
-void PlaybackSessionManagerProxy::setDefaultPlaybackRate(PlaybackSessionContextIdentifier contextId, float defaultPlaybackRate)
+void PlaybackSessionManagerProxy::setDefaultPlaybackRate(PlaybackSessionContextIdentifier contextId, double defaultPlaybackRate)
{
m_page->send(Messages::PlaybackSessionManager::SetDefaultPlaybackRate(contextId, defaultPlaybackRate));
}
-void PlaybackSessionManagerProxy::setPlaybackRate(PlaybackSessionContextIdentifier contextId, float playbackRate)
+void PlaybackSessionManagerProxy::setPlaybackRate(PlaybackSessionContextIdentifier contextId, double playbackRate)
{
m_page->send(Messages::PlaybackSessionManager::SetPlaybackRate(contextId, playbackRate));
}
Modified: trunk/Source/WebKit/UIProcess/ios/fullscreen/WKFullScreenViewController.mm (279042 => 279043)
--- trunk/Source/WebKit/UIProcess/ios/fullscreen/WKFullScreenViewController.mm 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebKit/UIProcess/ios/fullscreen/WKFullScreenViewController.mm 2021-06-18 19:15:40 UTC (rev 279043)
@@ -50,9 +50,9 @@
public:
void setParent(WKFullScreenViewController *parent) { m_parent = parent; }
- void rateChanged(bool isPlaying, float /* playbackRate */, float /* defaultPlaybackRate */) override
+ void rateChanged(OptionSet<WebCore::PlaybackSessionModel::PlaybackState> playbackState, double /* playbackRate */, double /* defaultPlaybackRate */) override
{
- m_parent.playing = isPlaying;
+ m_parent.playing = playbackState.contains(WebCore::PlaybackSessionModel::PlaybackState::Playing);
}
void isPictureInPictureSupportedChanged(bool) override
Modified: trunk/Source/WebKit/WebProcess/cocoa/PlaybackSessionManager.h (279042 => 279043)
--- trunk/Source/WebKit/WebProcess/cocoa/PlaybackSessionManager.h 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebKit/WebProcess/cocoa/PlaybackSessionManager.h 2021-06-18 19:15:40 UTC (rev 279043)
@@ -75,7 +75,7 @@
void currentTimeChanged(double currentTime, double anchorTime) final;
void bufferedTimeChanged(double) final;
void playbackStartedTimeChanged(double playbackStartedTime) final;
- void rateChanged(bool isPlaying, float playbackRate, float defaultPlaybackRate) final;
+ void rateChanged(OptionSet<WebCore::PlaybackSessionModel::PlaybackState>, double playbackRate, double defaultPlaybackRate) final;
void seekableRangesChanged(const WebCore::TimeRanges&, double lastModifiedTime, double liveUpdateInterval) final;
void canPlayFastReverseChanged(bool value) final;
void audioMediaSelectionOptionsChanged(const Vector<WebCore::MediaSelectionOption>& options, uint64_t selectedIndex) final;
@@ -130,7 +130,7 @@
void currentTimeChanged(PlaybackSessionContextIdentifier, double currentTime, double anchorTime);
void bufferedTimeChanged(PlaybackSessionContextIdentifier, double bufferedTime);
void playbackStartedTimeChanged(PlaybackSessionContextIdentifier, double playbackStartedTime);
- void rateChanged(PlaybackSessionContextIdentifier, bool isPlaying, float playbackRate, float defaultPlaybackRate);
+ void rateChanged(PlaybackSessionContextIdentifier, OptionSet<WebCore::PlaybackSessionModel::PlaybackState>, double playbackRate, double defaultPlaybackRate);
void seekableRangesChanged(PlaybackSessionContextIdentifier, const WebCore::TimeRanges&, double lastModifiedTime, double liveUpdateInterval);
void canPlayFastReverseChanged(PlaybackSessionContextIdentifier, bool value);
void audioMediaSelectionOptionsChanged(PlaybackSessionContextIdentifier, const Vector<WebCore::MediaSelectionOption>& options, uint64_t selectedIndex);
Modified: trunk/Source/WebKit/WebProcess/cocoa/PlaybackSessionManager.mm (279042 => 279043)
--- trunk/Source/WebKit/WebProcess/cocoa/PlaybackSessionManager.mm 2021-06-18 18:25:50 UTC (rev 279042)
+++ trunk/Source/WebKit/WebProcess/cocoa/PlaybackSessionManager.mm 2021-06-18 19:15:40 UTC (rev 279043)
@@ -76,10 +76,10 @@
m_manager->bufferedTimeChanged(m_contextId, bufferedTime);
}
-void PlaybackSessionInterfaceContext::rateChanged(bool isPlaying, float playbackRate, float defaultPlaybackRate)
+void PlaybackSessionInterfaceContext::rateChanged(OptionSet<PlaybackSessionModel::PlaybackState> playbackState, double playbackRate, double defaultPlaybackRate)
{
if (m_manager)
- m_manager->rateChanged(m_contextId, isPlaying, playbackRate, defaultPlaybackRate);
+ m_manager->rateChanged(m_contextId, playbackState, playbackRate, defaultPlaybackRate);
}
void PlaybackSessionInterfaceContext::playbackStartedTimeChanged(double playbackStartedTime)
@@ -341,9 +341,9 @@
m_page->send(Messages::PlaybackSessionManagerProxy::PlaybackStartedTimeChanged(contextId, playbackStartedTime));
}
-void PlaybackSessionManager::rateChanged(PlaybackSessionContextIdentifier contextId, bool isPlaying, float playbackRate, float defaultPlaybackRate)
+void PlaybackSessionManager::rateChanged(PlaybackSessionContextIdentifier contextId, OptionSet<PlaybackSessionModel::PlaybackState> playbackState, double playbackRate, double defaultPlaybackRate)
{
- m_page->send(Messages::PlaybackSessionManagerProxy::RateChanged(contextId, isPlaying, playbackRate, defaultPlaybackRate));
+ m_page->send(Messages::PlaybackSessionManagerProxy::RateChanged(contextId, playbackState, playbackRate, defaultPlaybackRate));
}
void PlaybackSessionManager::seekableRangesChanged(PlaybackSessionContextIdentifier contextId, const WebCore::TimeRanges& timeRanges, double lastModifiedTime, double liveUpdateInterval)