[Cocoa] Deactivate the audio session before the WebProcess suspends.
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 6 Apr 2019 01:08:50 +0000 (01:08 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 6 Apr 2019 01:08:50 +0000 (01:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=196658

Reviewed by Eric Carlson.

Source/WebCore:

Test: platform/mac/media/audio-session-deactivated-when-suspended.html

Deactivate the audio session when we are notified that the session will suspend.

Drive-by fix: don't try to begin playback when the process is suspended.

* platform/audio/PlatformMediaSessionManager.cpp:
(WebCore::PlatformMediaSessionManager::sessionWillBeginPlayback):
(WebCore::PlatformMediaSessionManager::processWillSuspend):
(WebCore::PlatformMediaSessionManager::processDidResume):
* platform/audio/PlatformMediaSessionManager.h:
(WebCore::PlatformMediaSessionManager::processIsSuspended const):
* testing/InternalSettings.cpp:
(WebCore::InternalSettings::Backup::Backup):
(WebCore::InternalSettings::Backup::restoreTo):
(WebCore::InternalSettings::setShouldDeactivateAudioSession):
* testing/InternalSettings.h:
* testing/InternalSettings.idl:
* testing/Internals.cpp:
(WebCore::Internals::processWillSuspend):
(WebCore::Internals::processDidResume):
* testing/Internals.h:
* testing/Internals.idl:

Source/WebKit:

Notify the PlatformMediaSessionManager when the process suspends or resumes.

* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::actualPrepareToSuspend):
(WebKit::WebProcess::cancelPrepareToSuspend):
(WebKit::WebProcess::processDidResume):

LayoutTests:

* platform/mac/media/audio-session-deactivated-when-suspended-expected.txt: Added.
* platform/mac/media/audio-session-deactivated-when-suspended.html: Added.

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

14 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac/media/audio-session-deactivated-when-suspended-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/media/audio-session-deactivated-when-suspended.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp
Source/WebCore/platform/audio/PlatformMediaSessionManager.h
Source/WebCore/testing/InternalSettings.cpp
Source/WebCore/testing/InternalSettings.h
Source/WebCore/testing/InternalSettings.idl
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl
Source/WebKit/ChangeLog
Source/WebKit/WebProcess/WebProcess.cpp

index e13d677..4a25ec3 100644 (file)
@@ -1,3 +1,13 @@
+2019-04-05  Jer Noble  <jer.noble@apple.com>
+
+        [Cocoa] Deactivate the audio session before the WebProcess suspends.
+        https://bugs.webkit.org/show_bug.cgi?id=196658
+
+        Reviewed by Eric Carlson.
+
+        * platform/mac/media/audio-session-deactivated-when-suspended-expected.txt: Added.
+        * platform/mac/media/audio-session-deactivated-when-suspended.html: Added.
+
 2019-04-05  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: TestSuite test cases should have their own timeout to ensure tests fail with output instead of timeout by test runner
diff --git a/LayoutTests/platform/mac/media/audio-session-deactivated-when-suspended-expected.txt b/LayoutTests/platform/mac/media/audio-session-deactivated-when-suspended-expected.txt
new file mode 100644 (file)
index 0000000..ba95d06
--- /dev/null
@@ -0,0 +1,13 @@
+
+RUN(internals.settings.setShouldDeactivateAudioSession(true))
+RUN(video = document.querySelector("video"))
+RUN(video.src = findMediaFile("video", "../../../media/content/test"))
+RUN(video.play())
+EVENT(playing)
+EXPECTED (internals.audioSessionActive() == 'true') OK
+RUN(internals.processWillSuspend())
+EXPECTED (internals.audioSessionActive() == 'false') OK
+RUN(internals.processDidResume())
+EXPECTED (internals.audioSessionActive() == 'true') OK
+END OF TEST
+
diff --git a/LayoutTests/platform/mac/media/audio-session-deactivated-when-suspended.html b/LayoutTests/platform/mac/media/audio-session-deactivated-when-suspended.html
new file mode 100644 (file)
index 0000000..f04b501
--- /dev/null
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+       <title>audio-session-deactivated-when-suspended</title>
+       <script src="../../../media/video-test.js"></script>
+       <script src="../../../media/media-file.js"></script>
+       <script>
+       window.addEventListener('load', async event => {
+               run('internals.settings.setShouldDeactivateAudioSession(true)');
+               run('video = document.querySelector("video")');
+               run('video.src = findMediaFile("video", "../../../media/content/test")');
+               runWithKeyDown('video.play()');
+               await waitFor(video, 'playing');
+               testExpected('internals.audioSessionActive()', true);
+               run('internals.processWillSuspend()');
+               testExpected('internals.audioSessionActive()', false);
+               run('internals.processDidResume()');
+               testExpected('internals.audioSessionActive()', true);
+               endTest();
+       });
+       </script>
+</head>
+<body>
+       <video controls></video>
+</body>
+</html>
\ No newline at end of file
index fe639d9..0bf4d33 100644 (file)
@@ -1,3 +1,34 @@
+2019-04-05  Jer Noble  <jer.noble@apple.com>
+
+        [Cocoa] Deactivate the audio session before the WebProcess suspends.
+        https://bugs.webkit.org/show_bug.cgi?id=196658
+
+        Reviewed by Eric Carlson.
+
+        Test: platform/mac/media/audio-session-deactivated-when-suspended.html
+
+        Deactivate the audio session when we are notified that the session will suspend.
+
+        Drive-by fix: don't try to begin playback when the process is suspended.
+
+        * platform/audio/PlatformMediaSessionManager.cpp:
+        (WebCore::PlatformMediaSessionManager::sessionWillBeginPlayback):
+        (WebCore::PlatformMediaSessionManager::processWillSuspend):
+        (WebCore::PlatformMediaSessionManager::processDidResume):
+        * platform/audio/PlatformMediaSessionManager.h:
+        (WebCore::PlatformMediaSessionManager::processIsSuspended const):
+        * testing/InternalSettings.cpp:
+        (WebCore::InternalSettings::Backup::Backup):
+        (WebCore::InternalSettings::Backup::restoreTo):
+        (WebCore::InternalSettings::setShouldDeactivateAudioSession):
+        * testing/InternalSettings.h:
+        * testing/InternalSettings.idl:
+        * testing/Internals.cpp:
+        (WebCore::Internals::processWillSuspend):
+        (WebCore::Internals::processDidResume):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2019-04-05  Sihui Liu  <sihui_liu@apple.com>
 
         [iOS] Web process gets suspended while holding locked database files
index 71140ba..9b0be57 100644 (file)
@@ -204,18 +204,25 @@ PlatformMediaSessionManager::SessionRestrictions PlatformMediaSessionManager::re
 
 bool PlatformMediaSessionManager::sessionWillBeginPlayback(PlatformMediaSession& session)
 {
-    ALWAYS_LOG(LOGIDENTIFIER, session.logIdentifier());
-    
     setCurrentSession(session);
 
     PlatformMediaSession::MediaType sessionType = session.mediaType();
     SessionRestrictions restrictions = m_restrictions[sessionType];
-    if (session.state() == PlatformMediaSession::Interrupted && restrictions & InterruptedPlaybackNotPermitted)
+    if (session.state() == PlatformMediaSession::Interrupted && restrictions & InterruptedPlaybackNotPermitted) {
+        ALWAYS_LOG(LOGIDENTIFIER, session.logIdentifier(), " returning false because session.state() is Interrupted, and InterruptedPlaybackNotPermitted");
+        return false;
+    }
+
+    if (m_processIsSuspended) {
+        ALWAYS_LOG(LOGIDENTIFIER, session.logIdentifier(), " returning false because process is suspended");
         return false;
+    }
 
 #if USE(AUDIO_SESSION)
-    if (activeAudioSessionRequired() && !AudioSession::sharedSession().tryToSetActive(true))
+    if (activeAudioSessionRequired() && !AudioSession::sharedSession().tryToSetActive(true)) {
+        ALWAYS_LOG(LOGIDENTIFIER, session.logIdentifier(), " returning false failed to set active AudioSession");
         return false;
+    }
 
     m_becameActive = true;
 #endif
@@ -232,6 +239,7 @@ bool PlatformMediaSessionManager::sessionWillBeginPlayback(PlatformMediaSession&
             oneSession.pauseSession();
     });
 
+    ALWAYS_LOG(LOGIDENTIFIER, session.logIdentifier(), " returning true");
     return true;
 }
     
@@ -362,6 +370,36 @@ void PlatformMediaSessionManager::applicationWillEnterForeground(bool suspendedU
     });
 }
 
+void PlatformMediaSessionManager::processWillSuspend()
+{
+    if (m_processIsSuspended)
+        return;
+    m_processIsSuspended = true;
+
+#if USE(AUDIO_SESSION)
+    if (m_becameActive && shouldDeactivateAudioSession()) {
+        AudioSession::sharedSession().tryToSetActive(false);
+        ALWAYS_LOG(LOGIDENTIFIER, "tried to set inactive AudioSession");
+        m_becameActive = false;
+    }
+#endif
+}
+
+void PlatformMediaSessionManager::processDidResume()
+{
+    if (!m_processIsSuspended)
+        return;
+    m_processIsSuspended = false;
+
+#if USE(AUDIO_SESSION)
+    if (!m_becameActive && activeAudioSessionRequired()) {
+        m_becameActive = AudioSession::sharedSession().tryToSetActive(true);
+        ALWAYS_LOG(LOGIDENTIFIER, "tried to set active AudioSession, ", m_becameActive ? "succeeded" : "failed");
+    }
+#endif
+}
+
+
 void PlatformMediaSessionManager::sessionIsPlayingToWirelessPlaybackTargetChanged(PlatformMediaSession& session)
 {
     if (!m_isApplicationInBackground || !(m_restrictions[session.mediaType()] & BackgroundProcessPlaybackRestricted))
index 135a8d1..51cd6a2 100644 (file)
@@ -57,6 +57,7 @@ public:
     static void updateNowPlayingInfoIfNecessary();
 
     WEBCORE_EXPORT static void setShouldDeactivateAudioSession(bool);
+    WEBCORE_EXPORT static bool shouldDeactivateAudioSession();
 
     virtual ~PlatformMediaSessionManager() = default;
 
@@ -84,6 +85,8 @@ public:
     WEBCORE_EXPORT void applicationDidBecomeActive() const;
     WEBCORE_EXPORT void applicationWillEnterForeground(bool suspendedUnderLock) const;
     WEBCORE_EXPORT void applicationDidEnterBackground(bool suspendedUnderLock) const;
+    WEBCORE_EXPORT void processWillSuspend();
+    WEBCORE_EXPORT void processDidResume();
 
     void stopAllMediaPlaybackForDocument(const Document*);
     WEBCORE_EXPORT void stopAllMediaPlaybackForProcess();
@@ -141,6 +144,8 @@ protected:
 
     AudioHardwareListener* audioHardwareListener() { return m_audioHardwareListener.get(); }
 
+    bool processIsSuspended() const { return m_processIsSuspended; }
+
 #if !RELEASE_LOG_DISABLED
     const Logger& logger() const final { return m_logger; }
     const void* logIdentifier() const final { return nullptr; }
@@ -166,8 +171,6 @@ private:
     void systemWillSleep() override;
     void systemDidWake() override;
 
-    static bool shouldDeactivateAudioSession();
-
     SessionRestrictions m_restrictions[PlatformMediaSession::MediaStreamCapturingAudio + 1];
     mutable Vector<PlatformMediaSession*> m_sessions;
     std::unique_ptr<RemoteCommandListener> m_remoteCommandListener;
@@ -183,6 +186,7 @@ private:
     mutable bool m_isApplicationInBackground { false };
     bool m_willIgnoreSystemInterruptions { false };
     mutable int m_iteratingOverSessions { 0 };
+    bool m_processIsSuspended { false };
 
 #if USE(AUDIO_SESSION)
     bool m_becameActive { false };
index ce34c0f..4afbd44 100644 (file)
@@ -36,6 +36,7 @@
 #include "LocaleToScriptMapping.h"
 #include "Page.h"
 #include "PageGroup.h"
+#include "PlatformMediaSessionManager.h"
 #include "RenderTheme.h"
 #include "RuntimeEnabledFeatures.h"
 #include "Settings.h"
@@ -97,6 +98,7 @@ InternalSettings::Backup::Backup(Settings& settings)
 #if ENABLE(ACCESSIBILITY_EVENTS)
     , m_accessibilityEventsEnabled(settings.accessibilityEventsEnabled())
 #endif
+    , m_shouldDeactivateAudioSession(PlatformMediaSessionManager::shouldDeactivateAudioSession())
     , m_userInterfaceDirectionPolicy(settings.userInterfaceDirectionPolicy())
     , m_systemLayoutDirection(settings.systemLayoutDirection())
     , m_pdfImageCachingPolicy(settings.pdfImageCachingPolicy())
@@ -202,6 +204,7 @@ void InternalSettings::Backup::restoreTo(Settings& settings)
     FontCache::singleton().setShouldMockBoldSystemFontForAccessibility(m_shouldMockBoldSystemFontForAccessibility);
     settings.setFrameFlattening(m_frameFlattening);
     settings.setIncompleteImageBorderEnabled(m_incompleteImageBorderEnabled);
+    PlatformMediaSessionManager::setShouldDeactivateAudioSession(m_shouldDeactivateAudioSession);
 #if ENABLE(ACCESSIBILITY_EVENTS)
     settings.setAccessibilityEventsEnabled(m_accessibilityEventsEnabled);
 #endif
@@ -972,6 +975,11 @@ bool InternalSettings::webAnimationsCSSIntegrationEnabled()
     return RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled();
 }
 
+void InternalSettings::setShouldDeactivateAudioSession(bool should)
+{
+    PlatformMediaSessionManager::setShouldDeactivateAudioSession(should);
+}
+
 // If you add to this class, make sure that you update the Backup class for test reproducability!
 
 }
index b6fc3c9..46cb844 100644 (file)
@@ -129,6 +129,8 @@ public:
 
     static bool webAnimationsCSSIntegrationEnabled();
 
+    void setShouldDeactivateAudioSession(bool);
+
 private:
     explicit InternalSettings(Page*);
 
@@ -196,6 +198,7 @@ private:
 #if ENABLE(ACCESSIBILITY_EVENTS)
         bool m_accessibilityEventsEnabled;
 #endif
+        bool m_shouldDeactivateAudioSession;
         UserInterfaceDirectionPolicy m_userInterfaceDirectionPolicy;
         TextDirection m_systemLayoutDirection;
         PDFImageCachingPolicy m_pdfImageCachingPolicy;
index 2d0e646..20f8916 100644 (file)
@@ -115,5 +115,6 @@ enum FontLoadTimingOverride { "Block", "Swap", "Failure" };
     [EnabledAtRuntime=WebAnimations] boolean webAnimationsCSSIntegrationEnabled();
 
     [MayThrowException] void setAccessibilityEventsEnabled(boolean enabled);
+    void setShouldDeactivateAudioSession(boolean shouldDeactivate);
 };
 
index 4f4d119..48ed82a 100644 (file)
@@ -4971,4 +4971,14 @@ void Internals::setAlwaysAllowLocalWebarchive(bool alwaysAllowLocalWebarchive)
     localFrame->loader().setAlwaysAllowLocalWebarchive(alwaysAllowLocalWebarchive);
 }
 
+void Internals::processWillSuspend()
+{
+    PlatformMediaSessionManager::sharedManager().processWillSuspend();
+}
+
+void Internals::processDidResume()
+{
+    PlatformMediaSessionManager::sharedManager().processDidResume();
+}
+
 } // namespace WebCore
index 60bf278..dd0c643 100644 (file)
@@ -803,6 +803,8 @@ public:
     Vector<CookieData> getCookies() const;
 
     void setAlwaysAllowLocalWebarchive(bool);
+    void processWillSuspend();
+    void processDidResume();
 
 private:
     explicit Internals(Document&);
index 6c4bfeb..5ad3b6f 100644 (file)
@@ -739,4 +739,7 @@ enum CompositingPolicy {
     sequence<CookieData> getCookies();
 
     void setAlwaysAllowLocalWebarchive(boolean alwaysAllowLocalWebarchive);
+
+    void processWillSuspend();
+    void processDidResume();
 };
index b3ec43a..1a062b5 100644 (file)
@@ -1,3 +1,17 @@
+2019-04-05  Jer Noble  <jer.noble@apple.com>
+
+        [Cocoa] Deactivate the audio session before the WebProcess suspends.
+        https://bugs.webkit.org/show_bug.cgi?id=196658
+
+        Reviewed by Eric Carlson.
+
+        Notify the PlatformMediaSessionManager when the process suspends or resumes.
+
+        * WebProcess/WebProcess.cpp:
+        (WebKit::WebProcess::actualPrepareToSuspend):
+        (WebKit::WebProcess::cancelPrepareToSuspend):
+        (WebKit::WebProcess::processDidResume):
+
 2019-04-05  Sihui Liu  <sihui_liu@apple.com>
 
         [iOS] Web process gets suspended while holding locked database files
index 61c161f..540beb6 100644 (file)
@@ -1453,6 +1453,7 @@ void WebProcess::actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend shou
 
 #if ENABLE(VIDEO)
     suspendAllMediaBuffering();
+    PlatformMediaSessionManager::sharedManager().processWillSuspend();
 #endif
 
     if (!m_suppressMemoryPressureHandler)
@@ -1519,6 +1520,7 @@ void WebProcess::cancelPrepareToSuspend()
 #endif
 
 #if ENABLE(VIDEO)
+    PlatformMediaSessionManager::sharedManager().processDidResume();
     resumeAllMediaBuffering();
 #endif
 
@@ -1592,6 +1594,7 @@ void WebProcess::processDidResume()
 #endif
 
 #if ENABLE(VIDEO)
+    PlatformMediaSessionManager::sharedManager().processDidResume();
     resumeAllMediaBuffering();
 #endif
 }