From 26e08408d7847dccb01e84f86da7eb848723877f Mon Sep 17 00:00:00 2001 From: Eric Carlson Date: Wed, 27 Apr 2022 20:18:06 +0000 Subject: [PATCH] [iOS] unable to start playing audio when device is locked https://bugs.webkit.org/show_bug.cgi?id=239812 Reviewed by Jer Noble. Source/WebCore: Updated media/audio-session-category.html. * platform/audio/cocoa/MediaSessionManagerCocoa.mm: (WebCore::MediaSessionManagerCocoa::updateSessionState): Choose the appropriate route sharing policy after choosing the audio session category because setting MediaPlayback+Default makes a process ineligible for NowPlaying, and starting playback in the background will be blocked. * platform/audio/mac/AudioSessionMac.h: * platform/audio/mac/AudioSessionMac.mm: (WebCore::AudioSessionMac::setCategory): Updated for testing. * testing/Internals.cpp: (WebCore::Internals::routeSharingPolicy const): Added accessor for testing. * testing/Internals.h: * testing/Internals.idl: LayoutTests: * media/audio-session-category-expected.txt: * media/audio-session-category.html: Canonical link: https://commits.webkit.org/250059@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@293530 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- LayoutTests/ChangeLog | 11 ++++++++ .../media/audio-session-category-expected.txt | 9 +++++++ LayoutTests/media/audio-session-category.html | 12 ++++++++- Source/WebCore/ChangeLog | 25 +++++++++++++++++++ .../audio/cocoa/MediaSessionManagerCocoa.mm | 12 ++++----- .../platform/audio/mac/AudioSessionMac.h | 3 ++- .../platform/audio/mac/AudioSessionMac.mm | 9 +++---- Source/WebCore/testing/Internals.cpp | 9 +++++++ Source/WebCore/testing/Internals.h | 9 +++++++ Source/WebCore/testing/Internals.idl | 8 ++++++ 10 files changed, 93 insertions(+), 14 deletions(-) diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog index 072491011807..8787ec9d817e 100644 --- a/LayoutTests/ChangeLog +++ b/LayoutTests/ChangeLog @@ -1,3 +1,14 @@ +2022-04-27 Eric Carlson + + [iOS] unable to start playing audio when device is locked + https://bugs.webkit.org/show_bug.cgi?id=239812 + + + Reviewed by Jer Noble. + + * media/audio-session-category-expected.txt: + * media/audio-session-category.html: + 2022-04-27 Karl Rackler [ macOS Debug wk2 ] fast/css/identical-logical-height-decl.html is a flaky image failure diff --git a/LayoutTests/media/audio-session-category-expected.txt b/LayoutTests/media/audio-session-category-expected.txt index aa4ebbffb77f..80ebeb78ad59 100644 --- a/LayoutTests/media/audio-session-category-expected.txt +++ b/LayoutTests/media/audio-session-category-expected.txt @@ -14,19 +14,23 @@ EXPECTED (internals.audioSessionCategory() == 'None') OK RUN(video.play()) EVENT(playing) EXPECTED (internals.audioSessionCategory() == 'None') OK +EXPECTED (internals.routeSharingPolicy() == 'Default') OK ** Check category when an unmuted element is playing. RUN(video.muted = false) EVENT(volumechange) EXPECTED (internals.audioSessionCategory() == 'MediaPlayback') OK +EXPECTED (internals.routeSharingPolicy() == 'LongFormAudio') OK ** Mute the element, check again after 500ms. RUN(video.pause()) RUN(video.muted = true) EXPECTED (internals.audioSessionCategory() == 'MediaPlayback') OK +EXPECTED (internals.routeSharingPolicy() == 'LongFormAudio') OK ** And check again after 3 seconds. EXPECTED (internals.audioSessionCategory() == 'None') OK +EXPECTED (internals.routeSharingPolicy() == 'Default') OK ** AudioContext test ** @@ -39,12 +43,15 @@ EXPECTED (internals.audioSessionCategory() == 'None') OK ** Check category after starting oscillator. EXPECTED (internals.audioSessionCategory() == 'AmbientSound') OK +EXPECTED (internals.routeSharingPolicy() == 'Default') OK ** Close the context, check again after 500ms. EXPECTED (internals.audioSessionCategory() == 'AmbientSound') OK +EXPECTED (internals.routeSharingPolicy() == 'Default') OK ** And check again after 3 seconds. EXPECTED (internals.audioSessionCategory() == 'None') OK +EXPECTED (internals.routeSharingPolicy() == 'Default') OK ** MediaStream test ** @@ -54,11 +61,13 @@ EXPECTED (internals.audioSessionCategory() == 'None') OK ** Check category when capturing. EXPECTED (internals.audioSessionCategory() == 'PlayAndRecord') OK +EXPECTED (internals.routeSharingPolicy() == 'Default') OK ** Check after MediaStream is attached to audio element. RUN(video.play()) EVENT(playing) EXPECTED (internals.audioSessionCategory() == 'PlayAndRecord') OK +EXPECTED (internals.routeSharingPolicy() == 'Default') OK ** Check after MediaStream muting audio track. EXPECTED (internals.audioSessionCategory() == 'PlayAndRecord') OK diff --git a/LayoutTests/media/audio-session-category.html b/LayoutTests/media/audio-session-category.html index dfecbcdcf0a3..d068e9e33cd2 100644 --- a/LayoutTests/media/audio-session-category.html +++ b/LayoutTests/media/audio-session-category.html @@ -36,19 +36,24 @@ runWithKeyDown(() => { run('video.play()') }); await waitFor(video, 'playing'); testExpected('internals.audioSessionCategory()', 'None'); - + testExpected('internals.routeSharingPolicy()', 'Default'); + consoleWrite('
** Check category when an unmuted element is playing.'); runWithKeyDown(() => { run('video.muted = false') }); await waitFor(video, 'volumechange'); testExpected('internals.audioSessionCategory()', 'MediaPlayback'); + testExpected('internals.routeSharingPolicy()', 'LongFormAudio'); consoleWrite('
** Mute the element, check again after 500ms.'); run('video.pause()'); runWithKeyDown(() => { run('video.muted = true') }); await sleepFor(500); testExpected('internals.audioSessionCategory()', 'MediaPlayback'); + testExpected('internals.routeSharingPolicy()', 'LongFormAudio'); await waitForCategory('None', 3, '
** And check again after 3 seconds.'); + testExpected('internals.routeSharingPolicy()', 'Default'); + video.src = ''; video.load(); } @@ -77,13 +82,16 @@ oscillator.start(0); await sleepFor(500); testExpected('internals.audioSessionCategory()', 'AmbientSound'); + testExpected('internals.routeSharingPolicy()', 'Default'); consoleWrite('
** Close the context, check again after 500ms.'); await context.close(); await sleepFor(500); testExpected('internals.audioSessionCategory()', 'AmbientSound'); + testExpected('internals.routeSharingPolicy()', 'Default'); await waitForCategory('None', 3, '
** And check again after 3 seconds.'); + testExpected('internals.routeSharingPolicy()', 'Default'); } async function testMediaStream() @@ -94,12 +102,14 @@ consoleWrite('
** Check category when capturing.'); let stream = await navigator.mediaDevices.getUserMedia({audio : true}); testExpected('internals.audioSessionCategory()', 'PlayAndRecord'); + testExpected('internals.routeSharingPolicy()', 'Default'); consoleWrite('
** Check after MediaStream is attached to audio element.'); video.srcObject = stream; runWithKeyDown(() => { run('video.play()') }); await waitFor(video, 'playing'); testExpected('internals.audioSessionCategory()', 'PlayAndRecord'); + testExpected('internals.routeSharingPolicy()', 'Default'); consoleWrite('
** Check after MediaStream muting audio track.'); const audioTrack = stream.getAudioTracks()[0]; diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog index cece01b9c02a..beca7aaad517 100644 --- a/Source/WebCore/ChangeLog +++ b/Source/WebCore/ChangeLog @@ -1,3 +1,28 @@ +2022-04-27 Eric Carlson + + [iOS] unable to start playing audio when device is locked + https://bugs.webkit.org/show_bug.cgi?id=239812 + + + Reviewed by Jer Noble. + + Updated media/audio-session-category.html. + + * platform/audio/cocoa/MediaSessionManagerCocoa.mm: + (WebCore::MediaSessionManagerCocoa::updateSessionState): Choose the appropriate + route sharing policy after choosing the audio session category because + setting MediaPlayback+Default makes a process ineligible for NowPlaying, and starting + playback in the background will be blocked. + + * platform/audio/mac/AudioSessionMac.h: + * platform/audio/mac/AudioSessionMac.mm: + (WebCore::AudioSessionMac::setCategory): Updated for testing. + + * testing/Internals.cpp: + (WebCore::Internals::routeSharingPolicy const): Added accessor for testing. + * testing/Internals.h: + * testing/Internals.idl: + 2022-04-27 Tim Nguyen Make -webkit-transform-style an alias of transform-style diff --git a/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.mm b/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.mm index 19c07b380eb3..620a8668c1a0 100644 --- a/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.mm +++ b/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.mm @@ -178,14 +178,12 @@ if (!DeprecatedGlobalSettings::shouldManageAudioSessionCategory()) return; - RouteSharingPolicy policy = RouteSharingPolicy::Default; auto category = AudioSession::CategoryType::None; if (captureCount || (isPlayingAudio && AudioSession::sharedSession().category() == AudioSession::CategoryType::PlayAndRecord)) category = AudioSession::CategoryType::PlayAndRecord; - else if (hasAudibleAudioOrVideoMediaType) { + else if (hasAudibleAudioOrVideoMediaType) category = AudioSession::CategoryType::MediaPlayback; - policy = RouteSharingPolicy::LongFormAudio; - } else if (webAudioCount) + else if (webAudioCount) category = AudioSession::CategoryType::AmbientSound; if (category == AudioSession::CategoryType::None && m_previousCategory != AudioSession::CategoryType::None) { @@ -197,9 +195,11 @@ } else m_delayCategoryChangeTimer.stop(); - m_previousCategory = category; + RouteSharingPolicy policy = (category == AudioSession::CategoryType::MediaPlayback) ? RouteSharingPolicy::LongFormAudio : RouteSharingPolicy::Default; + + ALWAYS_LOG(LOGIDENTIFIER, "setting category = ", category, ", policy = ", policy, ", previous category = ", m_previousCategory); - ALWAYS_LOG(LOGIDENTIFIER, "setting category = ", category, ", policy = ", policy); + m_previousCategory = category; AudioSession::sharedSession().setCategory(category, policy); } diff --git a/Source/WebCore/platform/audio/mac/AudioSessionMac.h b/Source/WebCore/platform/audio/mac/AudioSessionMac.h index 4d5efeb41830..f16ce9895eb7 100644 --- a/Source/WebCore/platform/audio/mac/AudioSessionMac.h +++ b/Source/WebCore/platform/audio/mac/AudioSessionMac.h @@ -50,6 +50,7 @@ class AudioSessionMac final : public AudioSession { // AudioSession CategoryType category() const final { return m_category; } + RouteSharingPolicy routeSharingPolicy() const { return m_policy; } void audioOutputDeviceChanged() final; void setIsPlayingToBluetoothOverride(std::optional) final; void setCategory(CategoryType, RouteSharingPolicy) final; @@ -58,7 +59,6 @@ class AudioSessionMac final : public AudioSession { size_t numberOfOutputChannels() const final; size_t maximumNumberOfOutputChannels() const final; bool tryToSetActiveInternal(bool) final; - RouteSharingPolicy routeSharingPolicy() const final; String routingContextUID() const final; size_t preferredBufferSize() const final; void setPreferredBufferSize(size_t) final; @@ -70,6 +70,7 @@ class AudioSessionMac final : public AudioSession { std::optional m_lastMutedState; mutable WeakHashSet m_configurationChangeObservers; AudioSession::CategoryType m_category { AudioSession::CategoryType::None }; + RouteSharingPolicy m_policy { RouteSharingPolicy::Default }; #if ENABLE(ROUTING_ARBITRATION) bool m_setupArbitrationOngoing { false }; bool m_inRoutingArbitration { false }; diff --git a/Source/WebCore/platform/audio/mac/AudioSessionMac.mm b/Source/WebCore/platform/audio/mac/AudioSessionMac.mm index d04c83d3a0a6..645e0762c579 100644 --- a/Source/WebCore/platform/audio/mac/AudioSessionMac.mm +++ b/Source/WebCore/platform/audio/mac/AudioSessionMac.mm @@ -209,7 +209,7 @@ static float defaultDeviceTransportIsBluetooth() #endif } -void AudioSessionMac::setCategory(CategoryType category, RouteSharingPolicy) +void AudioSessionMac::setCategory(CategoryType category, RouteSharingPolicy policy) { #if ENABLE(ROUTING_ARBITRATION) bool playingToBluetooth = defaultDeviceTransportIsBluetooth(); @@ -217,6 +217,7 @@ static float defaultDeviceTransportIsBluetooth() return; m_category = category; + m_policy = policy; if (m_setupArbitrationOngoing) { RELEASE_LOG_ERROR(Media, "AudioSessionMac::setCategory() - a beginArbitrationWithCategory is still ongoing"); @@ -254,6 +255,7 @@ static float defaultDeviceTransportIsBluetooth() }); #else m_category = category; + m_policy = policy; #endif } @@ -368,11 +370,6 @@ static float defaultDeviceTransportIsBluetooth() return true; } -RouteSharingPolicy AudioSessionMac::routeSharingPolicy() const -{ - return RouteSharingPolicy::Default; -} - String AudioSessionMac::routingContextUID() const { return emptyString(); diff --git a/Source/WebCore/testing/Internals.cpp b/Source/WebCore/testing/Internals.cpp index 21c3a500b8f7..e962e8d85d44 100644 --- a/Source/WebCore/testing/Internals.cpp +++ b/Source/WebCore/testing/Internals.cpp @@ -5683,6 +5683,15 @@ auto Internals::audioSessionCategory() const -> AudioSessionCategory #endif } +auto Internals::routeSharingPolicy() const -> RouteSharingPolicy +{ +#if USE(AUDIO_SESSION) + return AudioSession::sharedSession().routeSharingPolicy(); +#else + return RouteSharingPolicy::Default; +#endif +} + #if ENABLE(VIDEO) auto Internals::categoryAtMostRecentPlayback(HTMLMediaElement& element) const -> AudioSessionCategory { diff --git a/Source/WebCore/testing/Internals.h b/Source/WebCore/testing/Internals.h index 2aaab54c1801..dc3bd62aec40 100644 --- a/Source/WebCore/testing/Internals.h +++ b/Source/WebCore/testing/Internals.h @@ -902,6 +902,7 @@ class Internals final : public RefCounted, private ContextDestruction #if USE(AUDIO_SESSION) using AudioSessionCategory = WebCore::AudioSessionCategory; + using RouteSharingPolicy = WebCore::RouteSharingPolicy; #else enum class AudioSessionCategory : uint8_t { None, @@ -912,10 +913,18 @@ class Internals final : public RefCounted, private ContextDestruction PlayAndRecord, AudioProcessing, }; + + enum class RouteSharingPolicy : uint8_t { + Default, + LongFormAudio, + Independent, + LongFormVideo + }; #endif bool supportsAudioSession() const; AudioSessionCategory audioSessionCategory() const; + RouteSharingPolicy routeSharingPolicy() const; #if ENABLE(VIDEO) AudioSessionCategory categoryAtMostRecentPlayback(HTMLMediaElement&) const; #endif diff --git a/Source/WebCore/testing/Internals.idl b/Source/WebCore/testing/Internals.idl index b6abf461a144..9b00adedfb2a 100644 --- a/Source/WebCore/testing/Internals.idl +++ b/Source/WebCore/testing/Internals.idl @@ -115,6 +115,13 @@ enum AudioSessionCategory { "AudioProcessing" }; +enum RouteSharingPolicy { + "Default", + "LongFormAudio", + "Independent", + "LongFormVideo" +}; + enum AutoplayPolicy { "Default", "Allow", @@ -980,6 +987,7 @@ typedef (FetchRequest or FetchResponse) FetchObject; readonly attribute boolean supportsAudioSession; AudioSessionCategory audioSessionCategory(); [Conditional=VIDEO] AudioSessionCategory categoryAtMostRecentPlayback(HTMLMediaElement element); + RouteSharingPolicy routeSharingPolicy(); double preferredAudioBufferSize(); double currentAudioBufferSize();