- Revision
- 280298
- Author
- [email protected]
- Date
- 2021-07-26 10:51:09 -0700 (Mon, 26 Jul 2021)
Log Message
[iOS] All home screen web apps resume when any home screen web app is foregrounded
https://bugs.webkit.org/show_bug.cgi?id=228246
<rdar://72949281>
Reviewed by Eric Carlson.
Source/WebCore:
Test: media/video-page-visibility-restriction.html
On iOS, home screen web apps all run from the same UIProcess, SafariViewService. So when
one Web App is foregrounded, the SafariViewService itself is foregrounded, and all WKWebViews
(one for each Web App) are foregrounded as well, allowing all Web Apps to resume audio
playback. This is not ideal; ideally, all Web Apps will be allowed to continue to play
audio in the background. But until we can fix that bug, the current behavior of pausing
audio from Web App A when A is backgrounded, and resuming audio from A when Web App B is
foregrounded feels super broken.
Add a new WKPreference/WebPreference/Setting and matching MediaElementSession restriction
that will block playback of audible media elements when the media element's page is not
visible. When adopted by SafariViewService, this would keep multiple Web Apps (and indeed
SafariViewController pages) from starting playback when any other is foregrounded.
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::initializeMediaSession):
(WebCore::HTMLMediaElement::visibilityStateChanged):
* html/MediaElementSession.cpp:
(WebCore::MediaElementSession::visibilityChanged):
(WebCore::MediaElementSession::playbackStateChangePermitted const):
* html/MediaElementSession.h:
* platform/audio/PlatformMediaSession.h:
* testing/Internals.cpp:
(WebCore::Internals::setMediaElementRestrictions):
Source/WebKit:
Add a private WKPreference for setting the new WebPreference.
* UIProcess/API/Cocoa/WKPreferences.mm:
(-[WKPreferences _requiresPageVisibilityToPlayAudio]):
(-[WKPreferences _setRequiresPageVisibilityToPlayAudio:]):
* UIProcess/API/Cocoa/WKPreferencesPrivate.h:
Source/WTF:
* Scripts/Preferences/WebPreferences.yaml:
LayoutTests:
* media/video-page-visibility-restriction-expected.txt: Added.
* media/video-page-visibility-restriction.html: Added.
Modified Paths
Added Paths
Diff
Modified: trunk/LayoutTests/ChangeLog (280297 => 280298)
--- trunk/LayoutTests/ChangeLog 2021-07-26 17:24:09 UTC (rev 280297)
+++ trunk/LayoutTests/ChangeLog 2021-07-26 17:51:09 UTC (rev 280298)
@@ -1,3 +1,14 @@
+2021-07-26 Jer Noble <[email protected]>
+
+ [iOS] All home screen web apps resume when any home screen web app is foregrounded
+ https://bugs.webkit.org/show_bug.cgi?id=228246
+ <rdar://72949281>
+
+ Reviewed by Eric Carlson.
+
+ * media/video-page-visibility-restriction-expected.txt: Added.
+ * media/video-page-visibility-restriction.html: Added.
+
2021-07-26 Ziran Sun <[email protected]>
[css-grid] svg image as grid items should use the overriding logical width/height when defined to compute the logical height/width
Added: trunk/LayoutTests/media/video-page-visibility-restriction-expected.txt (0 => 280298)
--- trunk/LayoutTests/media/video-page-visibility-restriction-expected.txt (rev 0)
+++ trunk/LayoutTests/media/video-page-visibility-restriction-expected.txt 2021-07-26 17:51:09 UTC (rev 280298)
@@ -0,0 +1,14 @@
+
+RUN(internals.setMediaElementRestrictions(video, "RequirePageVisibilityToPlayAudio"))
+RUN(video.src = "" "content/test"))
+EVENT(canplaythrough)
+RUN(internals.setPageVisibility(false))
+RUN(promise = video.play())
+Promise rejected correctly OK
+RUN(internals.setPageVisibility(true))
+RUN(promise = video.play())
+Promise resolved OK
+RUN(internals.setPageVisibility(false))
+EVENT(pause)
+END OF TEST
+
Added: trunk/LayoutTests/media/video-page-visibility-restriction.html (0 => 280298)
--- trunk/LayoutTests/media/video-page-visibility-restriction.html (rev 0)
+++ trunk/LayoutTests/media/video-page-visibility-restriction.html 2021-07-26 17:51:09 UTC (rev 280298)
@@ -0,0 +1,37 @@
+<html>
+ <head>
+ <script src=""
+ <script src=""
+ <script>
+ window.addEventListener('load', async event => {
+ if (!window.internals) {
+ failTest('This test requires window.internals.');
+ return;
+ }
+
+ findMediaElement();
+
+ run('internals.setMediaElementRestrictions(video, "RequirePageVisibilityToPlayAudio")');
+ run('video.src = "" "content/test")');
+ await waitFor(video, 'canplaythrough');
+
+ run('internals.setPageVisibility(false)');
+ run('promise = video.play()');
+ await shouldReject(promise);
+
+ run('internals.setPageVisibility(true)');
+ run('promise = video.play()');
+ await shouldResolve(promise);
+
+ run('internals.setPageVisibility(false)');
+ await waitFor(video, 'pause');
+
+ endTest();
+ });
+ </script>
+ </head>
+
+ <body>
+ <video controls loop></video>
+ </body>
+</html>
Modified: trunk/Source/WTF/ChangeLog (280297 => 280298)
--- trunk/Source/WTF/ChangeLog 2021-07-26 17:24:09 UTC (rev 280297)
+++ trunk/Source/WTF/ChangeLog 2021-07-26 17:51:09 UTC (rev 280298)
@@ -1,3 +1,13 @@
+2021-07-26 Jer Noble <[email protected]>
+
+ [iOS] All home screen web apps resume when any home screen web app is foregrounded
+ https://bugs.webkit.org/show_bug.cgi?id=228246
+ <rdar://72949281>
+
+ Reviewed by Eric Carlson.
+
+ * Scripts/Preferences/WebPreferences.yaml:
+
2021-07-23 Chris Dumez <[email protected]>
SharedBuffer::takeData() is a bit dangerous
Modified: trunk/Source/WTF/Scripts/Preferences/WebPreferences.yaml (280297 => 280298)
--- trunk/Source/WTF/Scripts/Preferences/WebPreferences.yaml 2021-07-26 17:24:09 UTC (rev 280297)
+++ trunk/Source/WTF/Scripts/Preferences/WebPreferences.yaml 2021-07-26 17:51:09 UTC (rev 280298)
@@ -1770,6 +1770,16 @@
WebCore:
default: true
+RequiresPageVisibilityToPlayAudio:
+ type: bool
+ defaultValue:
+ WebKitLegacy:
+ default: false
+ WebKit:
+ default: false
+ WebCore:
+ default: false
+
RequiresUserGestureForAudioPlayback:
type: bool
webKitLegacyPreferenceKey: WebKitAudioPlaybackRequiresUserGesture
Modified: trunk/Source/WebCore/ChangeLog (280297 => 280298)
--- trunk/Source/WebCore/ChangeLog 2021-07-26 17:24:09 UTC (rev 280297)
+++ trunk/Source/WebCore/ChangeLog 2021-07-26 17:51:09 UTC (rev 280298)
@@ -1,3 +1,37 @@
+2021-07-26 Jer Noble <[email protected]>
+
+ [iOS] All home screen web apps resume when any home screen web app is foregrounded
+ https://bugs.webkit.org/show_bug.cgi?id=228246
+ <rdar://72949281>
+
+ Reviewed by Eric Carlson.
+
+ Test: media/video-page-visibility-restriction.html
+
+ On iOS, home screen web apps all run from the same UIProcess, SafariViewService. So when
+ one Web App is foregrounded, the SafariViewService itself is foregrounded, and all WKWebViews
+ (one for each Web App) are foregrounded as well, allowing all Web Apps to resume audio
+ playback. This is not ideal; ideally, all Web Apps will be allowed to continue to play
+ audio in the background. But until we can fix that bug, the current behavior of pausing
+ audio from Web App A when A is backgrounded, and resuming audio from A when Web App B is
+ foregrounded feels super broken.
+
+ Add a new WKPreference/WebPreference/Setting and matching MediaElementSession restriction
+ that will block playback of audible media elements when the media element's page is not
+ visible. When adopted by SafariViewService, this would keep multiple Web Apps (and indeed
+ SafariViewController pages) from starting playback when any other is foregrounded.
+
+ * html/HTMLMediaElement.cpp:
+ (WebCore::HTMLMediaElement::initializeMediaSession):
+ (WebCore::HTMLMediaElement::visibilityStateChanged):
+ * html/MediaElementSession.cpp:
+ (WebCore::MediaElementSession::visibilityChanged):
+ (WebCore::MediaElementSession::playbackStateChangePermitted const):
+ * html/MediaElementSession.h:
+ * platform/audio/PlatformMediaSession.h:
+ * testing/Internals.cpp:
+ (WebCore::Internals::setMediaElementRestrictions):
+
2021-07-26 Philippe Normand <[email protected]>
[Pipewire] Muting the display capture closes the Portal session
Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (280297 => 280298)
--- trunk/Source/WebCore/html/HTMLMediaElement.cpp 2021-07-26 17:24:09 UTC (rev 280297)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp 2021-07-26 17:51:09 UTC (rev 280298)
@@ -474,6 +474,9 @@
if (document.settings().invisibleAutoplayNotPermitted())
m_mediaSession->addBehaviorRestriction(MediaElementSession::InvisibleAutoplayNotPermitted);
+ if (document.settings().requiresPageVisibilityToPlayAudio())
+ m_mediaSession->addBehaviorRestriction(MediaElementSession::RequirePageVisibilityToPlayAudio);
+
if (document.ownerElement() || !document.isMediaDocument()) {
if (m_shouldVideoPlaybackRequireUserGesture) {
m_mediaSession->addBehaviorRestriction(MediaElementSession::RequireUserGestureForVideoRateChange);
@@ -5774,17 +5777,6 @@
mediaSession().visibilityChanged();
if (m_player)
m_player->setVisible(!m_elementIsHidden);
-
- bool isPlayingAudio = isPlaying() && hasAudio() && !muted() && volume();
- if (!isPlayingAudio) {
- if (m_elementIsHidden) {
- ALWAYS_LOG(LOGIDENTIFIER, "Suspending playback after going to the background");
- mediaSession().beginInterruption(PlatformMediaSession::EnteringBackground);
- } else {
- ALWAYS_LOG(LOGIDENTIFIER, "Resuming playback after entering foreground");
- mediaSession().endInterruption(PlatformMediaSession::MayResumePlaying);
- }
- }
}
bool HTMLMediaElement::requiresTextTrackRepresentation() const
Modified: trunk/Source/WebCore/html/MediaElementSession.cpp (280297 => 280298)
--- trunk/Source/WebCore/html/MediaElementSession.cpp 2021-07-26 17:24:09 UTC (rev 280297)
+++ trunk/Source/WebCore/html/MediaElementSession.cpp 2021-07-26 17:51:09 UTC (rev 280298)
@@ -249,10 +249,34 @@
{
scheduleClientDataBufferingCheck();
- if (m_element.elementIsHidden() && !m_element.isFullscreen())
+ bool elementIsHidden = m_element.elementIsHidden();
+
+ if (elementIsHidden && !m_element.isFullscreen())
m_elementIsHiddenUntilVisibleInViewport = true;
else if (m_element.isVisibleInViewport())
m_elementIsHiddenUntilVisibleInViewport = false;
+
+ bool isPlayingAudio = m_element.isPlaying() && m_element.hasAudio() && !m_element.muted() && m_element.volume();
+ if (!isPlayingAudio) {
+ if (elementIsHidden) {
+ ALWAYS_LOG(LOGIDENTIFIER, "Suspending silent playback after page visibility: hidden");
+ beginInterruption(PlatformMediaSession::EnteringBackground);
+ } else {
+ ALWAYS_LOG(LOGIDENTIFIER, "Resuming silent playback after page visibility: showing");
+ endInterruption(PlatformMediaSession::MayResumePlaying);
+ }
+ return;
+ }
+
+ if (hasBehaviorRestriction(RequirePageVisibilityToPlayAudio)) {
+ if (elementIsHidden) {
+ ALWAYS_LOG(LOGIDENTIFIER, "Suspending audible playback after page visibility: hidden");
+ beginInterruption(PlatformMediaSession::EnteringBackground);
+ } else {
+ ALWAYS_LOG(LOGIDENTIFIER, "Resuming audible playback after page visibility: showing");
+ endInterruption(PlatformMediaSession::MayResumePlaying);
+ }
+ }
}
void MediaElementSession::isVisibleInViewportChanged()
@@ -391,6 +415,11 @@
return makeUnexpected(MediaPlaybackDenialReason::UserGestureRequired);
}
+ if (m_restrictions & RequirePageVisibilityToPlayAudio && (!m_element.isVideo() || m_element.hasAudio()) && !m_element.muted() && m_element.volume() && m_element.elementIsHidden()) {
+ ALWAYS_LOG(LOGIDENTIFIER, "Returning FALSE because page visibility required for audio rate change restriction");
+ return makeUnexpected(MediaPlaybackDenialReason::UserGestureRequired);
+ }
+
if (m_restrictions & RequireUserGestureForVideoDueToLowPowerMode && m_element.isVideo() && !document.processingUserGestureForMedia()) {
ALWAYS_LOG(LOGIDENTIFIER, "Returning FALSE because of video low power mode restriction");
return makeUnexpected(MediaPlaybackDenialReason::UserGestureRequired);
Modified: trunk/Source/WebCore/html/MediaElementSession.h (280297 => 280298)
--- trunk/Source/WebCore/html/MediaElementSession.h 2021-07-26 17:24:09 UTC (rev 280297)
+++ trunk/Source/WebCore/html/MediaElementSession.h 2021-07-26 17:51:09 UTC (rev 280298)
@@ -129,6 +129,7 @@
RequireUserGestureToControlControlsManager = 1 << 13,
RequirePlaybackToControlControlsManager = 1 << 14,
RequireUserGestureForVideoDueToLowPowerMode = 1 << 15,
+ RequirePageVisibilityToPlayAudio = 1 << 16,
AllRestrictions = ~NoRestrictions,
};
typedef unsigned BehaviorRestrictions;
Modified: trunk/Source/WebCore/platform/audio/PlatformMediaSession.h (280297 => 280298)
--- trunk/Source/WebCore/platform/audio/PlatformMediaSession.h 2021-07-26 17:24:09 UTC (rev 280297)
+++ trunk/Source/WebCore/platform/audio/PlatformMediaSession.h 2021-07-26 17:51:09 UTC (rev 280298)
@@ -93,6 +93,7 @@
InvisibleAutoplay,
ProcessInactive,
PlaybackSuspended,
+ PageNotVisible,
};
InterruptionType interruptionType() const { return m_interruptionType; }
@@ -367,7 +368,8 @@
WebCore::PlatformMediaSession::InterruptionType::SuspendedUnderLock,
WebCore::PlatformMediaSession::InterruptionType::InvisibleAutoplay,
WebCore::PlatformMediaSession::InterruptionType::ProcessInactive,
- WebCore::PlatformMediaSession::InterruptionType::PlaybackSuspended
+ WebCore::PlatformMediaSession::InterruptionType::PlaybackSuspended,
+ WebCore::PlatformMediaSession::InterruptionType::PageNotVisible
>;
};
Modified: trunk/Source/WebCore/testing/Internals.cpp (280297 => 280298)
--- trunk/Source/WebCore/testing/Internals.cpp 2021-07-26 17:24:09 UTC (rev 280297)
+++ trunk/Source/WebCore/testing/Internals.cpp 2021-07-26 17:51:09 UTC (rev 280298)
@@ -4366,6 +4366,8 @@
restrictions |= MediaElementSession::RequirePlaybackToControlControlsManager;
if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforvideoduetolowpowermode"))
restrictions |= MediaElementSession::RequireUserGestureForVideoDueToLowPowerMode;
+ if (equalLettersIgnoringASCIICase(restrictionString, "requirepagevisibilitytoplayaudio"))
+ restrictions |= MediaElementSession::RequirePageVisibilityToPlayAudio;
}
element.mediaSession().addBehaviorRestriction(restrictions);
}
Modified: trunk/Source/WebKit/ChangeLog (280297 => 280298)
--- trunk/Source/WebKit/ChangeLog 2021-07-26 17:24:09 UTC (rev 280297)
+++ trunk/Source/WebKit/ChangeLog 2021-07-26 17:51:09 UTC (rev 280298)
@@ -1,3 +1,18 @@
+2021-07-26 Jer Noble <[email protected]>
+
+ [iOS] All home screen web apps resume when any home screen web app is foregrounded
+ https://bugs.webkit.org/show_bug.cgi?id=228246
+ <rdar://72949281>
+
+ Reviewed by Eric Carlson.
+
+ Add a private WKPreference for setting the new WebPreference.
+
+ * UIProcess/API/Cocoa/WKPreferences.mm:
+ (-[WKPreferences _requiresPageVisibilityToPlayAudio]):
+ (-[WKPreferences _setRequiresPageVisibilityToPlayAudio:]):
+ * UIProcess/API/Cocoa/WKPreferencesPrivate.h:
+
2021-07-26 Philippe Normand <[email protected]>
[GTK] MiniBrowser crashes when closed while capturing desktop
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm (280297 => 280298)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm 2021-07-26 17:24:09 UTC (rev 280297)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm 2021-07-26 17:51:09 UTC (rev 280298)
@@ -1507,6 +1507,16 @@
#endif
}
+- (BOOL)_requiresPageVisibilityToPlayAudio
+{
+ return _preferences->requiresPageVisibilityToPlayAudio();
+}
+
+- (void)_setRequiresPageVisibilityToPlayAudio:(BOOL)requires
+{
+ _preferences->setRequiresPageVisibilityToPlayAudio(requires);
+}
+
@end
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h (280297 => 280298)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h 2021-07-26 17:24:09 UTC (rev 280297)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h 2021-07-26 17:51:09 UTC (rev 280298)
@@ -172,8 +172,8 @@
@property (nonatomic, setter=_setPitchCorrectionAlgorithm:) _WKPitchCorrectionAlgorithm _pitchCorrectionAlgorithm WK_API_AVAILABLE(macos(12.0), ios(15.0));
@property (nonatomic, setter=_setMediaSessionEnabled:) BOOL _mediaSessionEnabled WK_API_AVAILABLE(macos(12.0), ios(15.0));
@property (nonatomic, getter=_isExtensibleSSOEnabled, setter=_setExtensibleSSOEnabled:) BOOL _extensibleSSOEnabled WK_API_AVAILABLE(macos(12.0), ios(15.0));
+@property (nonatomic, setter=_setRequiresPageVisibilityToPlayAudio:) BOOL _requiresPageVisibilityToPlayAudio WK_API_AVAILABLE(macos(12.0), ios(15.0));
-
#if !TARGET_OS_IPHONE
@property (nonatomic, setter=_setWebGLEnabled:) BOOL _webGLEnabled WK_API_AVAILABLE(macos(10.13.4));
@property (nonatomic, setter=_setJavaEnabledForLocalFiles:) BOOL _javaEnabledForLocalFiles WK_API_AVAILABLE(macos(10.13.4));