Title: [281367] trunk
Revision
281367
Author
you...@apple.com
Date
2021-08-21 00:01:21 -0700 (Sat, 21 Aug 2021)

Log Message

Prevent AudioSession category from moving out of PlayAndRecord too quickly
https://bugs.webkit.org/show_bug.cgi?id=229327
<rdar://81997024>

Reviewed by Eric Carlson.

Source/WebCore:

If category is PlayAndRecord, we stick to PlayAndRecord until audio is no longer playing at which point we
transition to whatever category is most appropriate.
Introduce PlatformMediaSession::isPlaying in addition to canProduceAudio to compute whether audio is being played.

Test: http/tests/media/media-stream/audio-capture-and-category.https.html

* Modules/webaudio/AudioContext.cpp:
(WebCore::AudioContext::isPlaying const):
* Modules/webaudio/AudioContext.h:
* html/HTMLMediaElement.h:
* platform/audio/PlatformMediaSession.cpp:
(WebCore::PlatformMediaSession::isPlaying const):
* platform/audio/PlatformMediaSession.h:
(WebCore::PlatformMediaSessionClient::isPlaying const):
* platform/audio/cocoa/MediaSessionManagerCocoa.mm:
(WebCore::MediaSessionManagerCocoa::updateSessionState):

LayoutTests:

* http/tests/media/media-stream/audio-capture-and-category.https-expected.txt: Added.
* http/tests/media/media-stream/audio-capture-and-category.https.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (281366 => 281367)


--- trunk/LayoutTests/ChangeLog	2021-08-21 06:10:53 UTC (rev 281366)
+++ trunk/LayoutTests/ChangeLog	2021-08-21 07:01:21 UTC (rev 281367)
@@ -1,3 +1,14 @@
+2021-08-21  Youenn Fablet  <you...@apple.com>
+
+        Prevent AudioSession category from moving out of PlayAndRecord too quickly
+        https://bugs.webkit.org/show_bug.cgi?id=229327
+        <rdar://81997024>
+
+        Reviewed by Eric Carlson.
+
+        * http/tests/media/media-stream/audio-capture-and-category.https-expected.txt: Added.
+        * http/tests/media/media-stream/audio-capture-and-category.https.html: Added.
+
 2021-08-20  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, reverting r281343.

Added: trunk/LayoutTests/http/tests/media/media-stream/audio-capture-and-category.https-expected.txt (0 => 281367)


--- trunk/LayoutTests/http/tests/media/media-stream/audio-capture-and-category.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/media/media-stream/audio-capture-and-category.https-expected.txt	2021-08-21 07:01:21 UTC (rev 281367)
@@ -0,0 +1,4 @@
+
+
+PASS Validate audio session category is set to PlayAndRecord after frame stopped capturing but continued playing audio
+

Added: trunk/LayoutTests/http/tests/media/media-stream/audio-capture-and-category.https.html (0 => 281367)


--- trunk/LayoutTests/http/tests/media/media-stream/audio-capture-and-category.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/media/media-stream/audio-capture-and-category.https.html	2021-08-21 07:01:21 UTC (rev 281367)
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<script src=""
+<script src=""
+</head>
+<body>
+<video id="audio" autoplay playsInline></video>
+<script>
+async function negotiate(pc1, pc2)
+{
+     pc1._onicecandidate_ = (event) => { pc2.addIceCandidate(event.candidate) };
+     pc2._onicecandidate_ = (event) => { pc1.addIceCandidate(event.candidate) };
+
+     const offer = await pc1.createOffer();
+     await pc1.setLocalDescription(offer);
+     await pc2.setRemoteDescription(offer);
+     const answer = await pc2.createAnswer();
+     await pc2.setLocalDescription(answer);
+     await pc1.setRemoteDescription(answer);
+}
+
+promise_test(async (t) => {
+     if (!window.internals)
+        return Promise.reject("Test require internals API");
+     internals.settings.setShouldManageAudioSessionCategory(true);
+
+     const stream = await navigator.mediaDevices.getUserMedia({audio:true});
+
+     let counter = 0;
+     while (++counter < 100 && internals.audioSessionCategory() !== "PlayAndRecord")
+         await new Promise(resolve => setTimeout(resolve, 50));
+     assert_equals(internals.audioSessionCategory(), "PlayAndRecord", "category when capturing and not playing audio");
+
+     const pc1 = new RTCPeerConnection();
+     const pc2 = new RTCPeerConnection();
+
+     pc1.addTrack(stream.getAudioTracks()[0], stream);
+
+     await negotiate(pc1, pc2);
+
+     // We play the remote track, which will stay live even if the microphone track gets stopped.
+     audio.srcObject = new MediaStream([pc2.getReceivers()[0].track]);
+     await audio.play();
+
+     assert_equals(internals.audioSessionCategory(), "PlayAndRecord", "category when capturing and audio is being played");
+
+     stream.getAudioTracks()[0].stop();
+
+     await new Promise(resolve => setTimeout(resolve, 1000));
+     assert_equals(internals.audioSessionCategory(), "PlayAndRecord", "category when capture has stopped but audio contines to play");
+
+     audio.pause();
+
+     counter = 0;
+     while (++counter < 100 && internals.audioSessionCategory() === "PlayAndRecord")
+         await new Promise(resolve => setTimeout(resolve, 50));
+     assert_not_equals(internals.audioSessionCategory(), "PlayAndRecord", "category when capture has stopped and audio stopped playing");
+}, "Validate audio session category is set to PlayAndRecord after frame stopped capturing but continued playing audio");
+</script>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (281366 => 281367)


--- trunk/Source/WebCore/ChangeLog	2021-08-21 06:10:53 UTC (rev 281366)
+++ trunk/Source/WebCore/ChangeLog	2021-08-21 07:01:21 UTC (rev 281367)
@@ -1,3 +1,28 @@
+2021-08-21  Youenn Fablet  <you...@apple.com>
+
+        Prevent AudioSession category from moving out of PlayAndRecord too quickly
+        https://bugs.webkit.org/show_bug.cgi?id=229327
+        <rdar://81997024>
+
+        Reviewed by Eric Carlson.
+
+        If category is PlayAndRecord, we stick to PlayAndRecord until audio is no longer playing at which point we
+        transition to whatever category is most appropriate.
+        Introduce PlatformMediaSession::isPlaying in addition to canProduceAudio to compute whether audio is being played.
+
+        Test: http/tests/media/media-stream/audio-capture-and-category.https.html
+
+        * Modules/webaudio/AudioContext.cpp:
+        (WebCore::AudioContext::isPlaying const):
+        * Modules/webaudio/AudioContext.h:
+        * html/HTMLMediaElement.h:
+        * platform/audio/PlatformMediaSession.cpp:
+        (WebCore::PlatformMediaSession::isPlaying const):
+        * platform/audio/PlatformMediaSession.h:
+        (WebCore::PlatformMediaSessionClient::isPlaying const):
+        * platform/audio/cocoa/MediaSessionManagerCocoa.mm:
+        (WebCore::MediaSessionManagerCocoa::updateSessionState):
+
 2021-08-20  Tim Nguyen  <n...@apple.com>
 
         Walk up stacking contexts in RenderLayerBacking::compositingOpacity

Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp (281366 => 281367)


--- trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp	2021-08-21 06:10:53 UTC (rev 281366)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp	2021-08-21 07:01:21 UTC (rev 281367)
@@ -485,6 +485,11 @@
     return !document() || document()->activeDOMObjectsAreSuspended() || document()->activeDOMObjectsAreStopped();
 }
 
+bool AudioContext::isPlaying() const
+{
+    return state() == State::Running;
+}
+
 void AudioContext::pageMutedStateDidChange()
 {
     if (document() && document()->page())

Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.h (281366 => 281367)


--- trunk/Source/WebCore/Modules/webaudio/AudioContext.h	2021-08-21 06:10:53 UTC (rev 281366)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.h	2021-08-21 07:01:21 UTC (rev 281367)
@@ -130,6 +130,7 @@
     bool shouldOverrideBackgroundPlaybackRestriction(PlatformMediaSession::InterruptionType) const final { return false; }
     bool canProduceAudio() const final { return true; }
     bool isSuspended() const final;
+    bool isPlaying() const final;
     MediaSessionGroupIdentifier mediaSessionGroupIdentifier() const final;
 
     // MediaCanStartListener.

Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (281366 => 281367)


--- trunk/Source/WebCore/html/HTMLMediaElement.h	2021-08-21 06:10:53 UTC (rev 281366)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h	2021-08-21 07:01:21 UTC (rev 281367)
@@ -457,7 +457,7 @@
     WEBCORE_EXPORT static void clearMediaCacheForOrigins(const String&, const HashSet<SecurityOriginData>&);
     static void resetMediaEngines();
 
-    bool isPlaying() const { return m_playing; }
+    bool isPlaying() const final { return m_playing; }
 
 #if ENABLE(WEB_AUDIO)
     MediaElementAudioSourceNode* audioSourceNode() { return m_audioSourceNode; }

Modified: trunk/Source/WebCore/platform/audio/PlatformMediaSession.cpp (281366 => 281367)


--- trunk/Source/WebCore/platform/audio/PlatformMediaSession.cpp	2021-08-21 06:10:53 UTC (rev 281366)
+++ trunk/Source/WebCore/platform/audio/PlatformMediaSession.cpp	2021-08-21 07:01:21 UTC (rev 281367)
@@ -322,6 +322,11 @@
     return m_client.isSuspended();
 }
 
+bool PlatformMediaSession::isPlaying() const
+{
+    return m_client.isPlaying();
+}
+
 bool PlatformMediaSession::shouldOverrideBackgroundLoadingRestriction() const
 {
     return m_client.shouldOverrideBackgroundLoadingRestriction();

Modified: trunk/Source/WebCore/platform/audio/PlatformMediaSession.h (281366 => 281367)


--- trunk/Source/WebCore/platform/audio/PlatformMediaSession.h	2021-08-21 06:10:53 UTC (rev 281366)
+++ trunk/Source/WebCore/platform/audio/PlatformMediaSession.h	2021-08-21 07:01:21 UTC (rev 281367)
@@ -158,6 +158,7 @@
 
     bool isHidden() const;
     bool isSuspended() const;
+    bool isPlaying() const;
 
     bool shouldOverrideBackgroundLoadingRestriction() const;
 
@@ -252,6 +253,7 @@
 
     virtual bool canProduceAudio() const { return false; }
     virtual bool isSuspended() const { return false; };
+    virtual bool isPlaying() const { return false; };
 
     virtual bool shouldOverrideBackgroundPlaybackRestriction(PlatformMediaSession::InterruptionType) const = 0;
     virtual bool shouldOverrideBackgroundLoadingRestriction() const { return false; }

Modified: trunk/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.mm (281366 => 281367)


--- trunk/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.mm	2021-08-21 06:10:53 UTC (rev 281366)
+++ trunk/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.mm	2021-08-21 07:01:21 UTC (rev 281367)
@@ -86,6 +86,7 @@
     int webAudioCount = 0;
     int captureCount = countActiveAudioCaptureSources();
     bool hasAudibleAudioOrVideoMediaType = false;
+    bool isPlayingAudio = false;
     forEachSession([&] (auto& session) mutable {
         auto type = session.mediaType();
         switch (type) {
@@ -101,16 +102,19 @@
             ++audioCount;
             break;
         case PlatformMediaSession::MediaType::WebAudio:
-            if (session.canProduceAudio())
+            if (session.canProduceAudio()) {
                 ++webAudioCount;
+                isPlayingAudio |= session.isPlaying();
+            }
             break;
         }
 
         if (!hasAudibleAudioOrVideoMediaType) {
-            if ((type == PlatformMediaSession::MediaType::VideoAudio || type == PlatformMediaSession::MediaType::Audio) && session.canProduceAudio() && session.hasPlayedSinceLastInterruption())
+            bool isPotentiallyAudible = session.isPlayingToWirelessPlaybackTarget() || ((type == PlatformMediaSession::MediaType::VideoAudio || type == PlatformMediaSession::MediaType::Audio) && session.canProduceAudio() && session.hasPlayedSinceLastInterruption());
+            if (isPotentiallyAudible) {
                 hasAudibleAudioOrVideoMediaType = true;
-            if (session.isPlayingToWirelessPlaybackTarget())
-                hasAudibleAudioOrVideoMediaType = true;
+                isPlayingAudio |= session.isPlaying();
+            }
         }
     });
 
@@ -138,7 +142,7 @@
 
     RouteSharingPolicy policy = RouteSharingPolicy::Default;
     auto category = AudioSession::CategoryType::None;
-    if (captureCount)
+    if (captureCount || (isPlayingAudio && AudioSession::sharedSession().category() == AudioSession::CategoryType::PlayAndRecord))
         category = AudioSession::CategoryType::PlayAndRecord;
     else if (hasAudibleAudioOrVideoMediaType) {
         category = AudioSession::CategoryType::MediaPlayback;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to