Diff
Modified: trunk/LayoutTests/ChangeLog (291758 => 291759)
--- trunk/LayoutTests/ChangeLog 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/LayoutTests/ChangeLog 2022-03-23 19:21:33 UTC (rev 291759)
@@ -1,3 +1,22 @@
+2022-03-23 Jer Noble <jer.no...@apple.com>
+
+ [iOS] WebKit app is sometimes not "Now Playing" during initial playback
+ https://bugs.webkit.org/show_bug.cgi?id=236993
+ <rdar://88827167>
+
+ Reviewed by Eric Carlson.
+
+ Fix the audio-session-category test. Creating the oscilator actually does change the
+ AudioSession category to "Ambient", but (previously) only in the next run loop, so a
+ synchronous test that the AudioSession category is "None" succeeds. Now that starting
+ playback (as happens when creating an audio node) changes the AudioSession synchronously,
+ the test begins failing.
+
+ * media/audio-session-category-at-most-recent-playback-expected.txt: Added.
+ * media/audio-session-category-at-most-recent-playback.html: Added.
+ * media/audio-session-category-expected.txt:
+ * media/audio-session-category.html:
+
2022-03-23 Matteo Flores <matteo_flo...@apple.com>
Unreviewed, reverting r291721.
Added: trunk/LayoutTests/media/audio-session-category-at-most-recent-playback-expected.txt (0 => 291759)
--- trunk/LayoutTests/media/audio-session-category-at-most-recent-playback-expected.txt (rev 0)
+++ trunk/LayoutTests/media/audio-session-category-at-most-recent-playback-expected.txt 2022-03-23 19:21:33 UTC (rev 291759)
@@ -0,0 +1,16 @@
+
+RUN(video.muted = true)
+RUN(video.src = "" "content/audio-tracks"))
+EVENT(canplaythrough)
+EXPECTED (internals.categoryAtMostRecentPlayback(video) == 'None') OK
+RUN(video.play())
+EVENT(playing)
+EXPECTED (internals.categoryAtMostRecentPlayback(video) == 'None') OK
+RUN(video.pause())
+EVENT(pause)
+RUN(video.muted = false)
+RUN(video.play())
+EVENT(playing)
+EXPECTED (internals.categoryAtMostRecentPlayback(video) == 'MediaPlayback') OK
+END OF TEST
+
Added: trunk/LayoutTests/media/audio-session-category-at-most-recent-playback.html (0 => 291759)
--- trunk/LayoutTests/media/audio-session-category-at-most-recent-playback.html (rev 0)
+++ trunk/LayoutTests/media/audio-session-category-at-most-recent-playback.html 2022-03-23 19:21:33 UTC (rev 291759)
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script src=""
+ <script src=""
+ <script>
+ window.addEventListener('load', async event => {
+ findMediaElement();
+
+ if (window.internals)
+ internals.settings.setShouldManageAudioSessionCategory(true);
+
+ run('video.muted = true');
+ run('video.src = "" "content/audio-tracks")');
+
+ await waitFor(video, 'canplaythrough');
+
+ testExpected('internals.categoryAtMostRecentPlayback(video)', 'None');
+
+ run('video.play()');
+ await waitFor(video, 'playing');
+ await sleepFor(500);
+
+ testExpected('internals.categoryAtMostRecentPlayback(video)', 'None');
+
+ run('video.pause()');
+ await waitFor(video, 'pause');
+
+ run('video.muted = false');
+ run('video.play()');
+ await waitFor(video, 'playing');
+ await sleepFor(500);
+ testExpected('internals.categoryAtMostRecentPlayback(video)', 'MediaPlayback');
+
+ endTest();
+ });
+ </script>
+</head>
+<body>
+ <video></video>
+</body>
+</html>
\ No newline at end of file
Modified: trunk/LayoutTests/media/audio-session-category-expected.txt (291758 => 291759)
--- trunk/LayoutTests/media/audio-session-category-expected.txt 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/LayoutTests/media/audio-session-category-expected.txt 2022-03-23 19:21:33 UTC (rev 291759)
@@ -34,7 +34,7 @@
** Check category before creating AudioContext.
EXPECTED (internals.audioSessionCategory() == 'None') OK
-** Check category after oscillator graph has been connected but not started.
+** Check category after AudioContext has been created but not started.
EXPECTED (internals.audioSessionCategory() == 'None') OK
** Check category after starting oscillator.
Modified: trunk/LayoutTests/media/audio-session-category.html (291758 => 291759)
--- trunk/LayoutTests/media/audio-session-category.html 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/LayoutTests/media/audio-session-category.html 2022-03-23 19:21:33 UTC (rev 291759)
@@ -58,11 +58,12 @@
consoleWrite('<br><br>** AudioContext test **');
await waitForCategory('None', 10, '<br>** Check category before creating AudioContext.');
- consoleWrite('<br>** Check category after oscillator graph has been connected but not started.');
+ consoleWrite('<br>** Check category after AudioContext has been created but not started.');
let context = new AudioContext();
+ testExpected('internals.audioSessionCategory()', 'None');
+
let oscillator = null;
let gainNode = context.createGain();
-
oscillator = context.createOscillator();
oscillator.type = 'square';
oscillator.frequency.setValueAtTime(440, context.currentTime);
@@ -70,9 +71,9 @@
oscillator.connect(gainNode);
gainNode.connect(context.destination);
gainNode.gain.value = 0.1
- testExpected('internals.audioSessionCategory()', 'None');
consoleWrite('<br>** Check category after starting oscillator.');
+ context.resume();
oscillator.start(0);
await sleepFor(500);
testExpected('internals.audioSessionCategory()', 'AmbientSound');
Modified: trunk/LayoutTests/platform/glib/TestExpectations (291758 => 291759)
--- trunk/LayoutTests/platform/glib/TestExpectations 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/LayoutTests/platform/glib/TestExpectations 2022-03-23 19:21:33 UTC (rev 291759)
@@ -1876,6 +1876,7 @@
# Tests behavior specific to MediaSessionManagerCocoa
media/audio-session-category.html [ Skip ]
+media/audio-session-category-at-most-recent-playback.html [ Skip ]
# This test assumes we cannot play RTSP, but we can.
media/unsupported-rtsp.html [ WontFix Skip ]
Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (291758 => 291759)
--- trunk/LayoutTests/platform/mac-wk1/TestExpectations 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations 2022-03-23 19:21:33 UTC (rev 291759)
@@ -65,6 +65,7 @@
http/tests/navigation/page-cache-getUserMedia-pending-promise.html [ Skip ]
http/tests/navigation/page-cache-mediastream.html [ Skip ]
media/audio-session-category.html [ Skip ]
+media/audio-session-category-at-most-recent-playback.html [ Skip ]
# Shared workers are only implemented for WebKit2.
imported/w3c/web-platform-tests/content-security-policy/connect-src/shared-worker-connect-src-allowed.sub.html [ Skip ]
Modified: trunk/Source/WebCore/ChangeLog (291758 => 291759)
--- trunk/Source/WebCore/ChangeLog 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/Source/WebCore/ChangeLog 2022-03-23 19:21:33 UTC (rev 291759)
@@ -1,3 +1,64 @@
+2022-03-23 Jer Noble <jer.no...@apple.com>
+
+ [iOS] WebKit app is sometimes not "Now Playing" during initial playback
+ https://bugs.webkit.org/show_bug.cgi?id=236993
+ <rdar://88827167>
+
+ Reviewed by Eric Carlson.
+
+ Test: media/audio-session-category-at-most-recent-playback.html
+
+ Recently, we have added the concept of "preparingToPlay" to PlatformMediaSession to allow
+ the correct category to be set if updateSessionState() is called after playback is allowed
+ by the MediaSessionManager, but before playback is actually started by the media element.
+ However, this depends on updateSessionState() being called synchronously during playback.
+ We disabled this synchronous update in r269077 due to the large runtime cost when a large
+ number of media elements are created (but not used) at once.
+
+ Relax this asynchronous update in the case where the state is moving to "Playing", which
+ ensures that the correct AudioSessionCategory is set before playback starts, rather than
+ immediately afterward.
+
+ To support testing that the category was correctly set before playback started, add an
+ ivar to HTMLMediaElement that is set to the current AudioSessionCategory immediately before
+ the media element instructs the MediaPlayer to start playback. Expose this ivar to Internals.
+
+ Drive-by fixes: AudioSession::CategoryType cannot be forward declared, as it is a public
+ member of a class. Allow the enum to be forward declared by moving the declaration outside
+ the class, but allow current uses of the enum to continue by typedefing it inside the class
+ to the original enum name. Add an IDL enumeration matching the AudioSession one in Interals.idl
+ and convert the existing audioSessionCategory() call to use the new enumeration.
+
+ (Unforunately in the case where USE_AUDIO_SESSION is not set, the enumeration must be re-
+ declared. This can be removed and the entire implementation wrapped in a USE() check, once
+ the bindings generator is extended to allow "Conditional="-style attributes for USE checks.)
+
+ The added test is flakey due to a previous change which would keep the MediaSession category
+ in "MediaPlayback" for up to 2s after playback ends. To counteract this flakiness, reset the
+ state of the PlatformMediaSessionManager between tests.
+
+ * html/HTMLMediaElement.cpp:
+ (WebCore::m_categoryAtMostRecentPlayback):
+ (WebCore::HTMLMediaElement::playPlayer):
+ (WebCore::m_logIdentifier): Deleted.
+ * html/HTMLMediaElement.h:
+ (WebCore::HTMLMediaElement::categoryAtMostRecentPlayback const):
+ * platform/audio/AudioSession.h:
+ * platform/audio/PlatformMediaSessionManager.cpp:
+ (WebCore::PlatformMediaSessionManager::sessionStateChanged):
+ * platform/audio/PlatformMediaSessionManager.h:
+ (WebCore::PlatformMediaSessionManager::resetSessionState):
+ * platform/audio/cocoa/MediaSessionManagerCocoa.h:
+ * platform/audio/cocoa/MediaSessionManagerCocoa.mm:
+ (WebCore::MediaSessionManagerCocoa::resetSessionState):
+ * testing/Internals.cpp:
+ (WebCore::Internals::resetToConsistentState):
+ * testing/Internals.cpp:
+ (WebCore::Internals::audioSessionCategory const):
+ (WebCore::Internals::categoryAtMostRecentPlayback const):
+ * testing/Internals.h:
+ * testing/Internals.idl:
+
2022-03-22 Brandon Stewart <brandonstew...@apple.com>
WBR element should set Clear property to None
Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (291758 => 291759)
--- trunk/Source/WebCore/html/HTMLMediaElement.cpp 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp 2022-03-23 19:21:33 UTC (rev 291759)
@@ -130,6 +130,10 @@
#include <wtf/Ref.h>
#include <wtf/text/CString.h>
+#if USE(AUDIO_SESSION)
+#include "AudioSession.h"
+#endif
+
#if ENABLE(WEB_AUDIO)
#include "AudioSourceProvider.h"
#include "MediaElementAudioSourceNode.h"
@@ -458,6 +462,9 @@
, m_logger(&document.logger())
, m_logIdentifier(uniqueLogIdentifier())
#endif
+#if USE(AUDIO_SESSION)
+ , m_categoryAtMostRecentPlayback(AudioSessionCategory::None)
+#endif
{
allMediaElements().add(this);
@@ -5694,6 +5701,10 @@
if (!m_player)
return;
+#if USE(AUDIO_SESSION)
+ m_categoryAtMostRecentPlayback = AudioSession::sharedSession().category();
+#endif
+
#if ENABLE(MEDIA_SESSION) && ENABLE(MEDIA_SESSION_COORDINATOR)
do {
if (!m_player->supportsPlayAtHostTime())
Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (291758 => 291759)
--- trunk/Source/WebCore/html/HTMLMediaElement.h 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h 2022-03-23 19:21:33 UTC (rev 291759)
@@ -605,6 +605,10 @@
WEBCORE_EXPORT bool mediaPlayerRenderingCanBeAccelerated() final;
+#if USE(AUDIO_SESSION)
+ WEBCORE_EXPORT AudioSessionCategory categoryAtMostRecentPlayback() const { return m_categoryAtMostRecentPlayback; }
+#endif
+
protected:
HTMLMediaElement(const QualifiedName&, Document&, bool createdByParser);
virtual ~HTMLMediaElement();
@@ -1239,6 +1243,10 @@
String m_audioOutputHashedDeviceId;
#endif
String m_id;
+
+#if USE(AUDIO_SESSION)
+ AudioSessionCategory m_categoryAtMostRecentPlayback;
+#endif
};
String convertEnumerationToString(HTMLMediaElement::AutoplayEventPlaybackState);
Modified: trunk/Source/WebCore/platform/audio/AudioSession.h (291758 => 291759)
--- trunk/Source/WebCore/platform/audio/AudioSession.h 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/Source/WebCore/platform/audio/AudioSession.h 2022-03-23 19:21:33 UTC (rev 291759)
@@ -46,6 +46,16 @@
LongFormVideo
};
+enum class AudioSessionCategory : uint8_t {
+ None,
+ AmbientSound,
+ SoloAmbientSound,
+ MediaPlayback,
+ RecordAudio,
+ PlayAndRecord,
+ AudioProcessing,
+};
+
class AudioSessionRoutingArbitrationClient;
class WEBCORE_EXPORT AudioSession {
@@ -63,15 +73,7 @@
virtual ~AudioSession();
- enum class CategoryType : uint8_t {
- None,
- AmbientSound,
- SoloAmbientSound,
- MediaPlayback,
- RecordAudio,
- PlayAndRecord,
- AudioProcessing,
- };
+ using CategoryType = AudioSessionCategory;
virtual void setCategory(CategoryType, RouteSharingPolicy);
virtual CategoryType category() const;
Modified: trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp (291758 => 291759)
--- trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp 2022-03-23 19:21:33 UTC (rev 291759)
@@ -290,9 +290,14 @@
ALWAYS_LOG(LOGIDENTIFIER, "session moved from index ", pausingSessionIndex, " to ", lastPlayingSessionIndex);
}
-void PlatformMediaSessionManager::sessionStateChanged(PlatformMediaSession&)
+void PlatformMediaSessionManager::sessionStateChanged(PlatformMediaSession& session)
{
- scheduleUpdateSessionState();
+ // Call updateSessionState() synchronously if the new state is Playing to ensure
+ // the audio session is active and has the correct category before playback starts.
+ if (session.state() == PlatformMediaSession::Playing)
+ updateSessionState();
+ else
+ scheduleUpdateSessionState();
}
void PlatformMediaSessionManager::setCurrentSession(PlatformMediaSession& session)
Modified: trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.h (291758 => 291759)
--- trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.h 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.h 2022-03-23 19:21:33 UTC (rev 291759)
@@ -168,6 +168,7 @@
WEBCORE_EXPORT void processSystemDidWake();
virtual void resetHaveEverRegisteredAsNowPlayingApplicationForTesting() { };
+ virtual void resetSessionState() { };
bool isApplicationInBackground() const { return m_isApplicationInBackground; }
Modified: trunk/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.h (291758 => 291759)
--- trunk/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.h 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.h 2022-03-23 19:21:33 UTC (rev 291759)
@@ -99,6 +99,7 @@
RemoteCommandListener::RemoteCommandsSet supportedCommands() const final;
void resetHaveEverRegisteredAsNowPlayingApplicationForTesting() final { m_haveEverRegisteredAsNowPlayingApplication = false; };
+ void resetSessionState() final;
private:
#if !RELEASE_LOG_DISABLED
Modified: trunk/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.mm (291758 => 291759)
--- trunk/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.mm 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.mm 2022-03-23 19:21:33 UTC (rev 291759)
@@ -204,6 +204,14 @@
updateSessionState();
}
+void MediaSessionManagerCocoa::resetSessionState()
+{
+ ALWAYS_LOG(LOGIDENTIFIER);
+ m_delayCategoryChangeTimer.stop();
+ m_previousCategory = AudioSession::CategoryType::None;
+ m_previousHadAudibleAudioOrVideoMediaType = false;
+}
+
void MediaSessionManagerCocoa::beginInterruption(PlatformMediaSession::InterruptionType type)
{
if (type == PlatformMediaSession::InterruptionType::SystemInterruption) {
Modified: trunk/Source/WebCore/testing/Internals.cpp (291758 => 291759)
--- trunk/Source/WebCore/testing/Internals.cpp 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/Source/WebCore/testing/Internals.cpp 2022-03-23 19:21:33 UTC (rev 291759)
@@ -554,6 +554,7 @@
page.group().ensureCaptionPreferences().setCaptionsStyleSheetOverride(emptyString());
PlatformMediaSessionManager::sharedManager().resetHaveEverRegisteredAsNowPlayingApplicationForTesting();
PlatformMediaSessionManager::sharedManager().resetRestrictions();
+ PlatformMediaSessionManager::sharedManager().resetSessionState();
PlatformMediaSessionManager::sharedManager().setWillIgnoreSystemInterruptions(true);
#endif
#if ENABLE(VIDEO) || ENABLE(WEB_AUDIO)
@@ -5658,29 +5659,26 @@
#endif
}
-String Internals::audioSessionCategory() const
+auto Internals::audioSessionCategory() const -> AudioSessionCategory
{
#if USE(AUDIO_SESSION)
- switch (AudioSession::sharedSession().category()) {
- case AudioSession::CategoryType::AmbientSound:
- return "AmbientSound"_s;
- case AudioSession::CategoryType::SoloAmbientSound:
- return "SoloAmbientSound"_s;
- case AudioSession::CategoryType::MediaPlayback:
- return "MediaPlayback"_s;
- case AudioSession::CategoryType::RecordAudio:
- return "RecordAudio"_s;
- case AudioSession::CategoryType::PlayAndRecord:
- return "PlayAndRecord"_s;
- case AudioSession::CategoryType::AudioProcessing:
- return "AudioProcessing"_s;
- case AudioSession::CategoryType::None:
- return "None"_s;
- }
+ return AudioSession::sharedSession().category();
+#else
+ return AudioSessionCategory::None;
#endif
- return emptyString();
}
+#if ENABLE(VIDEO)
+auto Internals::categoryAtMostRecentPlayback(HTMLMediaElement& element) const -> AudioSessionCategory
+{
+#if USE(AUDIO_SESSION)
+ return element.categoryAtMostRecentPlayback();
+#else
+ return AudioSessionCategory::None;
+#endif
+}
+#endif
+
double Internals::preferredAudioBufferSize() const
{
#if USE(AUDIO_SESSION)
Modified: trunk/Source/WebCore/testing/Internals.h (291758 => 291759)
--- trunk/Source/WebCore/testing/Internals.h 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/Source/WebCore/testing/Internals.h 2022-03-23 19:21:33 UTC (rev 291759)
@@ -47,6 +47,10 @@
#include "MediaUniqueIdentifier.h"
#endif
+#if USE(AUDIO_SESSION)
+#include "AudioSession.h"
+#endif
+
OBJC_CLASS DDScannerResult;
OBJC_CLASS VKCImageAnalysis;
@@ -889,8 +893,26 @@
bool shouldAudioTrackPlay(const AudioTrack&);
#endif
+
+#if USE(AUDIO_SESSION)
+ using AudioSessionCategory = WebCore::AudioSessionCategory;
+#else
+ enum class AudioSessionCategory : uint8_t {
+ None,
+ AmbientSound,
+ SoloAmbientSound,
+ MediaPlayback,
+ RecordAudio,
+ PlayAndRecord,
+ AudioProcessing,
+ };
+#endif
+
bool supportsAudioSession() const;
- String audioSessionCategory() const;
+ AudioSessionCategory audioSessionCategory() const;
+#if ENABLE(VIDEO)
+ AudioSessionCategory categoryAtMostRecentPlayback(HTMLMediaElement&) const;
+#endif
double preferredAudioBufferSize() const;
double currentAudioBufferSize() const;
bool audioSessionActive() const;
Modified: trunk/Source/WebCore/testing/Internals.idl (291758 => 291759)
--- trunk/Source/WebCore/testing/Internals.idl 2022-03-23 18:58:22 UTC (rev 291758)
+++ trunk/Source/WebCore/testing/Internals.idl 2022-03-23 19:21:33 UTC (rev 291759)
@@ -105,6 +105,16 @@
"Timeout"
};
+enum AudioSessionCategory {
+ "None",
+ "AmbientSound",
+ "SoloAmbientSound",
+ "MediaPlayback",
+ "RecordAudio",
+ "PlayAndRecord",
+ "AudioProcessing"
+};
+
enum AutoplayPolicy {
"Default",
"Allow",
@@ -966,7 +976,9 @@
undefined setConsoleMessageListener(StringCallback callback);
readonly attribute boolean supportsAudioSession;
- DOMString audioSessionCategory();
+ AudioSessionCategory audioSessionCategory();
+ [Conditional=VIDEO] AudioSessionCategory categoryAtMostRecentPlayback(HTMLMediaElement element);
+
double preferredAudioBufferSize();
double currentAudioBufferSize();
boolean audioSessionActive();