A HTMLMediaElement created while page is interrupted should be able to autoplay
https://bugs.webkit.org/show_bug.cgi?id=241783
Patch by Youenn Fablet <youennf@gmail.com> on 2022-06-21
Reviewed by Eric Carlson.
Previously, a session created while manager is interrupted would get its state set to interrupted.
When end of interruption happens, it would not be restarted since its interruption count would be set to 0.
Instead, manager now stores the last interruption.
In case of a new session, we now call beginInterruption instead of setting the session state directly.
This allows to have an interruption count set to 1 and thus uninterrupt the session when the end of interruption signal happens.
Covered by added test.
* LayoutTests/fast/mediastream/video-created-while-interrupted-expected.txt: Added.
* LayoutTests/fast/mediastream/video-created-while-interrupted.html: Added.
* Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp:
(WebCore::PlatformMediaSessionManager::beginInterruption):
(WebCore::PlatformMediaSessionManager::endInterruption):
(WebCore::PlatformMediaSessionManager::addSession):
(WebCore::PlatformMediaSessionManager::sessionWillBeginPlayback):
(WebCore::PlatformMediaSessionManager::processSystemWillSleep):
(WebCore::PlatformMediaSessionManager::processSystemDidWake):
* Source/WebCore/platform/audio/PlatformMediaSessionManager.h:
(WebCore::PlatformMediaSessionManager::isInterrupted const):
Canonical link: https://commits.webkit.org/251691@main
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@295686 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/fast/mediastream/video-created-while-interrupted-expected.txt b/LayoutTests/fast/mediastream/video-created-while-interrupted-expected.txt
new file mode 100644
index 0000000..69dd46c
--- /dev/null
+++ b/LayoutTests/fast/mediastream/video-created-while-interrupted-expected.txt
@@ -0,0 +1,4 @@
+
+
+PASS Correctly handle autoplay for a media element created while page is interrupted
+
diff --git a/LayoutTests/fast/mediastream/video-created-while-interrupted.html b/LayoutTests/fast/mediastream/video-created-while-interrupted.html
new file mode 100644
index 0000000..ae6f3de
--- /dev/null
+++ b/LayoutTests/fast/mediastream/video-created-while-interrupted.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Capture source interruption.</title>
+ <script src="../../resources/testharness.js"></script>
+ <script src="../../resources/testharnessreport.js"></script>
+ </head>
+<body>
+ <script>
+ promise_test(async (test) => {
+ if (window.internals)
+ internals.beginAudioSessionInterruption();
+
+ const video = document.createElement('video');
+ video.autoplay = true;
+ document.body.appendChild(video);
+
+ const stream = await navigator.mediaDevices.getUserMedia({audio: true});
+ video.srcObject = stream;
+
+ let counter = 0;
+ while(++counter < 100 && video.paused)
+ await new Promise(resolve => setTimeout(resolve, 50));
+
+ assert_false(video.paused);
+ }, "Correctly handle autoplay for a media element created while page is interrupted");
+ </script>
+</body>
+</html>
diff --git a/Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp b/Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp
index 1f5abb9..fa61cde 100644
--- a/Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp
+++ b/Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp
@@ -156,7 +156,7 @@
{
ALWAYS_LOG(LOGIDENTIFIER);
- m_interrupted = true;
+ m_currentInterruption = type;
forEachSession([type] (auto& session) {
session.beginInterruption(type);
});
@@ -167,7 +167,7 @@
{
ALWAYS_LOG(LOGIDENTIFIER);
- m_interrupted = false;
+ m_currentInterruption = { };
forEachSession([flags] (auto& session) {
session.endInterruption(flags);
});
@@ -177,8 +177,8 @@
{
ALWAYS_LOG(LOGIDENTIFIER, session.logIdentifier());
m_sessions.append(session);
- if (m_interrupted)
- session.setState(PlatformMediaSession::Interrupted);
+ if (m_currentInterruption)
+ session.beginInterruption(*m_currentInterruption);
#if !RELEASE_LOG_DISABLED
m_logger->addLogger(session.logger());
@@ -243,7 +243,7 @@
return false;
}
- if (m_interrupted)
+ if (m_currentInterruption)
endInterruption(PlatformMediaSession::NoFlags);
if (restrictions & ConcurrentPlaybackNotPermitted) {
@@ -455,7 +455,7 @@
void PlatformMediaSessionManager::processSystemWillSleep()
{
- if (m_interrupted)
+ if (m_currentInterruption)
return;
forEachSession([] (auto& session) {
@@ -465,7 +465,7 @@
void PlatformMediaSessionManager::processSystemDidWake()
{
- if (m_interrupted)
+ if (m_currentInterruption)
return;
forEachSession([] (auto& session) {
diff --git a/Source/WebCore/platform/audio/PlatformMediaSessionManager.h b/Source/WebCore/platform/audio/PlatformMediaSessionManager.h
index 79ea1ee..e3f034e 100644
--- a/Source/WebCore/platform/audio/PlatformMediaSessionManager.h
+++ b/Source/WebCore/platform/audio/PlatformMediaSessionManager.h
@@ -157,7 +157,7 @@
WEBCORE_EXPORT void processDidReceiveRemoteControlCommand(PlatformMediaSession::RemoteControlCommandType, const PlatformMediaSession::RemoteCommandArgument&);
- bool isInterrupted() const { return m_interrupted; }
+ bool isInterrupted() const { return !!m_currentInterruption; }
bool hasNoSession() const;
virtual void addSupportedCommand(PlatformMediaSession::RemoteControlCommandType) { };
@@ -209,7 +209,7 @@
SessionRestrictions m_restrictions[static_cast<unsigned>(PlatformMediaSession::MediaType::WebAudio) + 1];
mutable Vector<WeakPtr<PlatformMediaSession>> m_sessions;
- bool m_interrupted { false };
+ std::optional<PlatformMediaSession::InterruptionType> m_currentInterruption;
mutable bool m_isApplicationInBackground { false };
bool m_willIgnoreSystemInterruptions { false };
bool m_processIsSuspended { false };