Title: [245712] trunk
Revision
245712
Author
[email protected]
Date
2019-05-23 13:56:56 -0700 (Thu, 23 May 2019)

Log Message

Multiple videos (with audios) with autoplay & playinline not working. Only one video play at a time.
https://bugs.webkit.org/show_bug.cgi?id=193312
<rdar://problem/47189864>

Reviewed by Jer Noble.

Source/WebCore:

Allow all MediaStream backed video elements to play together.
Any non MediaStream backed video will stop all MediaStream backed video elements.
Conversely, all non MediaStream backed videos will stop when playing one MediaStream backed video.

Refactor PlatformMediaSessionManager as the way to iterate through sessions
is not safe when pausing a session: if playing, the session will be moved in the array of sessions.

To handle this, copy the list of sessions before iterating through them.
For extra safety, make sessions WeakPtr.

Add routines for the case of filtering with a predicate taking a const session.
In that case, we do not copy the vector but iterate through it as a small optimization.

Test: webrtc/concurrentVideoPlayback.html

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::bestMediaElementForShowingPlaybackControlsManager):
(WebCore::HTMLMediaElement::hasMediaStreamSource const):
* html/HTMLMediaElement.h:
* platform/audio/PlatformMediaSession.cpp:
(WebCore::PlatformMediaSession::activeAudioSessionRequired const):
(WebCore::PlatformMediaSession::canPlayConcurrently const):
(WebCore::PlatformMediaSession::activeAudioSessionRequired): Deleted.
* platform/audio/PlatformMediaSession.h:
(WebCore::PlatformMediaSessionClient::hasMediaStreamSource const):
* platform/audio/PlatformMediaSessionManager.cpp:
(WebCore::PlatformMediaSessionManager::has const):
(WebCore::PlatformMediaSessionManager::activeAudioSessionRequired const):
(WebCore::PlatformMediaSessionManager::canProduceAudio const):
(WebCore::PlatformMediaSessionManager::count const):
(WebCore::PlatformMediaSessionManager::beginInterruption):
(WebCore::PlatformMediaSessionManager::endInterruption):
(WebCore::PlatformMediaSessionManager::addSession):
(WebCore::PlatformMediaSessionManager::removeSession):
(WebCore::PlatformMediaSessionManager::sessionWillBeginPlayback):
(WebCore::PlatformMediaSessionManager::sessionWillEndPlayback):
(WebCore::PlatformMediaSessionManager::setCurrentSession):
(WebCore::PlatformMediaSessionManager::currentSession const):
(WebCore::PlatformMediaSessionManager::applicationWillBecomeInactive):
(WebCore::PlatformMediaSessionManager::applicationDidBecomeActive):
(WebCore::PlatformMediaSessionManager::applicationDidEnterBackground):
(WebCore::PlatformMediaSessionManager::applicationWillEnterForeground):
(WebCore::PlatformMediaSessionManager::systemWillSleep):
(WebCore::PlatformMediaSessionManager::systemDidWake):
(WebCore::PlatformMediaSessionManager::stopAllMediaPlaybackForDocument):
(WebCore::PlatformMediaSessionManager::stopAllMediaPlaybackForProcess):
(WebCore::PlatformMediaSessionManager::suspendAllMediaPlaybackForDocument):
(WebCore::PlatformMediaSessionManager::resumeAllMediaPlaybackForDocument):
(WebCore::PlatformMediaSessionManager::suspendAllMediaBufferingForDocument):
(WebCore::PlatformMediaSessionManager::resumeAllMediaBufferingForDocument):
(WebCore::PlatformMediaSessionManager::currentSessionsMatching const):
(WebCore::PlatformMediaSessionManager::forEachMatchingSession):
(WebCore::PlatformMediaSessionManager::forEachMatchingSession const):
(WebCore::PlatformMediaSessionManager::forEachSession):
(WebCore::PlatformMediaSessionManager::anyOfSessions const):
(): Deleted.
(WebCore::PlatformMediaSessionManager::applicationWillBecomeInactive const): Deleted.
(WebCore::PlatformMediaSessionManager::applicationDidBecomeActive const): Deleted.
(WebCore::PlatformMediaSessionManager::applicationDidEnterBackground const): Deleted.
(WebCore::PlatformMediaSessionManager::applicationWillEnterForeground const): Deleted.
(WebCore::PlatformMediaSessionManager::forEachSession const): Deleted.
(WebCore::PlatformMediaSessionManager::findSession const): Deleted.
* platform/audio/PlatformMediaSessionManager.h:
(WebCore::PlatformMediaSessionManager::anyOfSessions const): Deleted.
* platform/audio/cocoa/MediaSessionManagerCocoa.mm:
(MediaSessionManagerCocoa::updateSessionState):
(MediaSessionManagerCocoa::beginInterruption):
* platform/audio/ios/MediaSessionManagerIOS.mm:
(WebCore::MediaSessionManageriOS::configureWireLessTargetMonitoring):
(WebCore::MediaSessionManageriOS::externalOutputDeviceAvailableDidChange):

LayoutTests:

* webrtc/concurrentVideoPlayback-expected.txt: Added.
* webrtc/concurrentVideoPlayback.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (245711 => 245712)


--- trunk/LayoutTests/ChangeLog	2019-05-23 20:44:06 UTC (rev 245711)
+++ trunk/LayoutTests/ChangeLog	2019-05-23 20:56:56 UTC (rev 245712)
@@ -1,3 +1,14 @@
+2019-05-23  Youenn Fablet  <[email protected]>
+
+        Multiple videos (with audios) with autoplay & playinline not working. Only one video play at a time.
+        https://bugs.webkit.org/show_bug.cgi?id=193312
+        <rdar://problem/47189864>
+
+        Reviewed by Jer Noble.
+
+        * webrtc/concurrentVideoPlayback-expected.txt: Added.
+        * webrtc/concurrentVideoPlayback.html: Added.
+
 2019-05-23  Shawn Roberts  <[email protected]>
 
         Updating test expectations for failing tests.

Added: trunk/LayoutTests/webrtc/concurrentVideoPlayback-expected.txt (0 => 245712)


--- trunk/LayoutTests/webrtc/concurrentVideoPlayback-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webrtc/concurrentVideoPlayback-expected.txt	2019-05-23 20:56:56 UTC (rev 245712)
@@ -0,0 +1,7 @@
+  
+
+PASS Basic audio/video exchange 
+PASS Play MediaStream backed streams concurrently 
+PASS Play regular video content should pause MediaStream backed video elements 
+PASS Play MediaStream backed video elements should pause regular video content 
+

Added: trunk/LayoutTests/webrtc/concurrentVideoPlayback.html (0 => 245712)


--- trunk/LayoutTests/webrtc/concurrentVideoPlayback.html	                        (rev 0)
+++ trunk/LayoutTests/webrtc/concurrentVideoPlayback.html	2019-05-23 20:56:56 UTC (rev 245712)
@@ -0,0 +1,80 @@
+<!doctype html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>Testing concurrent video playing</title>
+        <script src=""
+        <script src=""
+        <script src=""
+    </head>
+    <body>
+        <video id="video1" autoplay controls></video>
+        <video id="video2" autoplay controls></video>
+        <video id="video3" autoplay controls></video>
+        <script src =""
+        <script>
+promise_test(async (test) => {
+    if (window.testRunner)
+        testRunner.setUserMediaPermission(true);
+
+    localStream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
+
+    const remoteStream = await new Promise((resolve, reject) => {
+        createConnections((firstConnection) => {
+            firstConnection.addTrack(localStream.getVideoTracks()[0], localStream);
+            firstConnection.addTrack(localStream.getAudioTracks()[0], localStream);
+        }, (secondConnection) => {
+            secondConnection._ontrack_ = (trackEvent) => {
+                resolve(trackEvent.streams[0]);
+            };
+        });
+        setTimeout(() => reject("Test timed out"), 5000);
+    });
+
+    video1.srcObject = localStream;
+    video2.srcObject = remoteStream;
+}, "Basic audio/video exchange");
+
+promise_test(async (test) => {
+    await video1.play();
+    await video2.play();
+
+    assert_false(video1.paused, "video1 paused");
+    assert_false(video2.paused, "video2 paused");
+}, "Play MediaStream backed streams concurrently");
+
+promise_test(async (test) => {
+
+    if (window.internals)
+        internals.setMediaSessionRestrictions('videoaudio', 'ConcurrentPlaybackNotPermitted');
+
+    video3.src = "" '../media/content/audio-tracks');
+    await video3.play();
+
+    let counter = 0;
+    while (!video1.paused && ++counter < 20)
+        await new Promise(resolve => setTimeout(resolve, 50));
+
+    assert_true(video1.paused, "video1 paused");
+    assert_true(video2.paused, "video2 paused");
+    assert_false(video3.paused, "video3 paused");
+}, "Play regular video content should pause MediaStream backed video elements");
+
+promise_test(async (test) => {
+    await video1.play();
+
+    assert_true(video3.paused, "video3 paused");
+
+    await video2.play();
+
+    let counter = 0;
+    while (!video3.paused && ++counter < 20)
+        await new Promise(resolve => setTimeout(resolve, 50));
+
+    assert_false(video1.paused, "video1 paused");
+    assert_false(video2.paused, "video2 paused");
+    assert_true(video3.paused, "video3 paused");
+}, "Play MediaStream backed video elements should pause regular video content");
+        </script>
+    </body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (245711 => 245712)


--- trunk/Source/WebCore/ChangeLog	2019-05-23 20:44:06 UTC (rev 245711)
+++ trunk/Source/WebCore/ChangeLog	2019-05-23 20:56:56 UTC (rev 245712)
@@ -1,3 +1,82 @@
+2019-05-23  Youenn Fablet  <[email protected]>
+
+        Multiple videos (with audios) with autoplay & playinline not working. Only one video play at a time.
+        https://bugs.webkit.org/show_bug.cgi?id=193312
+        <rdar://problem/47189864>
+
+        Reviewed by Jer Noble.
+
+        Allow all MediaStream backed video elements to play together.
+        Any non MediaStream backed video will stop all MediaStream backed video elements.
+        Conversely, all non MediaStream backed videos will stop when playing one MediaStream backed video.
+
+        Refactor PlatformMediaSessionManager as the way to iterate through sessions
+        is not safe when pausing a session: if playing, the session will be moved in the array of sessions.
+
+        To handle this, copy the list of sessions before iterating through them.
+        For extra safety, make sessions WeakPtr.
+
+        Add routines for the case of filtering with a predicate taking a const session.
+        In that case, we do not copy the vector but iterate through it as a small optimization.
+
+        Test: webrtc/concurrentVideoPlayback.html
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::bestMediaElementForShowingPlaybackControlsManager):
+        (WebCore::HTMLMediaElement::hasMediaStreamSource const):
+        * html/HTMLMediaElement.h:
+        * platform/audio/PlatformMediaSession.cpp:
+        (WebCore::PlatformMediaSession::activeAudioSessionRequired const):
+        (WebCore::PlatformMediaSession::canPlayConcurrently const):
+        (WebCore::PlatformMediaSession::activeAudioSessionRequired): Deleted.
+        * platform/audio/PlatformMediaSession.h:
+        (WebCore::PlatformMediaSessionClient::hasMediaStreamSource const):
+        * platform/audio/PlatformMediaSessionManager.cpp:
+        (WebCore::PlatformMediaSessionManager::has const):
+        (WebCore::PlatformMediaSessionManager::activeAudioSessionRequired const):
+        (WebCore::PlatformMediaSessionManager::canProduceAudio const):
+        (WebCore::PlatformMediaSessionManager::count const):
+        (WebCore::PlatformMediaSessionManager::beginInterruption):
+        (WebCore::PlatformMediaSessionManager::endInterruption):
+        (WebCore::PlatformMediaSessionManager::addSession):
+        (WebCore::PlatformMediaSessionManager::removeSession):
+        (WebCore::PlatformMediaSessionManager::sessionWillBeginPlayback):
+        (WebCore::PlatformMediaSessionManager::sessionWillEndPlayback):
+        (WebCore::PlatformMediaSessionManager::setCurrentSession):
+        (WebCore::PlatformMediaSessionManager::currentSession const):
+        (WebCore::PlatformMediaSessionManager::applicationWillBecomeInactive):
+        (WebCore::PlatformMediaSessionManager::applicationDidBecomeActive):
+        (WebCore::PlatformMediaSessionManager::applicationDidEnterBackground):
+        (WebCore::PlatformMediaSessionManager::applicationWillEnterForeground):
+        (WebCore::PlatformMediaSessionManager::systemWillSleep):
+        (WebCore::PlatformMediaSessionManager::systemDidWake):
+        (WebCore::PlatformMediaSessionManager::stopAllMediaPlaybackForDocument):
+        (WebCore::PlatformMediaSessionManager::stopAllMediaPlaybackForProcess):
+        (WebCore::PlatformMediaSessionManager::suspendAllMediaPlaybackForDocument):
+        (WebCore::PlatformMediaSessionManager::resumeAllMediaPlaybackForDocument):
+        (WebCore::PlatformMediaSessionManager::suspendAllMediaBufferingForDocument):
+        (WebCore::PlatformMediaSessionManager::resumeAllMediaBufferingForDocument):
+        (WebCore::PlatformMediaSessionManager::currentSessionsMatching const):
+        (WebCore::PlatformMediaSessionManager::forEachMatchingSession):
+        (WebCore::PlatformMediaSessionManager::forEachMatchingSession const):
+        (WebCore::PlatformMediaSessionManager::forEachSession):
+        (WebCore::PlatformMediaSessionManager::anyOfSessions const):
+        (): Deleted.
+        (WebCore::PlatformMediaSessionManager::applicationWillBecomeInactive const): Deleted.
+        (WebCore::PlatformMediaSessionManager::applicationDidBecomeActive const): Deleted.
+        (WebCore::PlatformMediaSessionManager::applicationDidEnterBackground const): Deleted.
+        (WebCore::PlatformMediaSessionManager::applicationWillEnterForeground const): Deleted.
+        (WebCore::PlatformMediaSessionManager::forEachSession const): Deleted.
+        (WebCore::PlatformMediaSessionManager::findSession const): Deleted.
+        * platform/audio/PlatformMediaSessionManager.h:
+        (WebCore::PlatformMediaSessionManager::anyOfSessions const): Deleted.
+        * platform/audio/cocoa/MediaSessionManagerCocoa.mm:
+        (MediaSessionManagerCocoa::updateSessionState):
+        (MediaSessionManagerCocoa::beginInterruption):
+        * platform/audio/ios/MediaSessionManagerIOS.mm:
+        (WebCore::MediaSessionManageriOS::configureWireLessTargetMonitoring):
+        (WebCore::MediaSessionManageriOS::externalOutputDeviceAvailableDidChange):
+
 2019-05-23  Saam barati  <[email protected]>
 
         [WHLSL] Add a helper for in-place AST mutation

Modified: trunk/Source/WebCore/dom/Document.cpp (245711 => 245712)


--- trunk/Source/WebCore/dom/Document.cpp	2019-05-23 20:44:06 UTC (rev 245711)
+++ trunk/Source/WebCore/dom/Document.cpp	2019-05-23 20:56:56 UTC (rev 245712)
@@ -1694,7 +1694,7 @@
 void Document::stopAllMediaPlayback()
 {
     if (auto* platformMediaSessionManager = PlatformMediaSessionManager::sharedManagerIfExists())
-        platformMediaSessionManager->stopAllMediaPlaybackForDocument(this);
+        platformMediaSessionManager->stopAllMediaPlaybackForDocument(*this);
 }
 
 void Document::suspendAllMediaPlayback()

Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (245711 => 245712)


--- trunk/Source/WebCore/html/HTMLMediaElement.cpp	2019-05-23 20:44:06 UTC (rev 245711)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp	2019-05-23 20:56:56 UTC (rev 245712)
@@ -657,19 +657,17 @@
 }
 RefPtr<HTMLMediaElement> HTMLMediaElement::bestMediaElementForShowingPlaybackControlsManager(MediaElementSession::PlaybackControlsPurpose purpose)
 {
-    auto allSessions = PlatformMediaSessionManager::sharedManager().currentSessionsMatching([] (const PlatformMediaSession& session) {
-        return is<MediaElementSession>(session);
-    });
-
     Vector<MediaElementSessionInfo> candidateSessions;
     bool atLeastOneNonCandidateMayBeConfusedForMainContent = false;
-    for (auto& session : allSessions) {
-        auto mediaElementSessionInfo = mediaElementSessionInfoForSession(downcast<MediaElementSession>(*session), purpose);
+    PlatformMediaSessionManager::sharedManager().forEachMatchingSession([](auto& session) {
+        return is<MediaElementSession>(session);
+    }, [&](auto& session) {
+        auto mediaElementSessionInfo = mediaElementSessionInfoForSession(downcast<MediaElementSession>(session), purpose);
         if (mediaElementSessionInfo.canShowControlsManager)
             candidateSessions.append(mediaElementSessionInfo);
         else if (mediaSessionMayBeConfusedWithMainContent(mediaElementSessionInfo, purpose))
             atLeastOneNonCandidateMayBeConfusedForMainContent = true;
-    }
+    });
 
     if (!candidateSessions.size())
         return nullptr;
@@ -8137,6 +8135,15 @@
     return m_bufferingPolicy;    
 }
 
+bool HTMLMediaElement::hasMediaStreamSource() const
+{
+#if ENABLE(MEDIA_STREAM)
+    return hasMediaStreamSrcObject();
+#else
+    return false;
+#endif
 }
 
+}
+
 #endif

Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (245711 => 245712)


--- trunk/Source/WebCore/html/HTMLMediaElement.h	2019-05-23 20:44:06 UTC (rev 245711)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h	2019-05-23 20:56:56 UTC (rev 245712)
@@ -892,6 +892,7 @@
     bool shouldOverrideBackgroundLoadingRestriction() const override;
     bool canProduceAudio() const final;
     bool processingUserGestureForMedia() const final;
+    bool hasMediaStreamSource() const final;
 
     void pageMutedStateDidChange() override;
 

Modified: trunk/Source/WebCore/platform/audio/PlatformMediaSession.cpp (245711 => 245712)


--- trunk/Source/WebCore/platform/audio/PlatformMediaSession.cpp	2019-05-23 20:44:06 UTC (rev 245711)
+++ trunk/Source/WebCore/platform/audio/PlatformMediaSession.cpp	2019-05-23 20:56:56 UTC (rev 245712)
@@ -342,7 +342,7 @@
     return m_client.displayType();
 }
 
-bool PlatformMediaSession::activeAudioSessionRequired()
+bool PlatformMediaSession::activeAudioSessionRequired() const
 {
     if (mediaType() == PlatformMediaSession::None)
         return false;
@@ -388,6 +388,11 @@
     PlatformMediaSessionManager::sharedManager().clientCharacteristicsChanged(*this);
 }
 
+bool PlatformMediaSession::canPlayConcurrently(const PlatformMediaSession& otherSession) const
+{
+    return m_client.hasMediaStreamSource() && otherSession.m_client.hasMediaStreamSource();
+}
+
 #if !RELEASE_LOG_DISABLED
 WTFLogChannel& PlatformMediaSession::logChannel() const
 {

Modified: trunk/Source/WebCore/platform/audio/PlatformMediaSession.h (245711 => 245712)


--- trunk/Source/WebCore/platform/audio/PlatformMediaSession.h	2019-05-23 20:44:06 UTC (rev 245711)
+++ trunk/Source/WebCore/platform/audio/PlatformMediaSession.h	2019-05-23 20:56:56 UTC (rev 245712)
@@ -29,6 +29,7 @@
 #include "Timer.h"
 #include <wtf/LoggerHelper.h>
 #include <wtf/Noncopyable.h>
+#include <wtf/WeakPtr.h>
 #include <wtf/text/WTFString.h>
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
@@ -42,8 +43,9 @@
 class PlatformMediaSessionClient;
 
 class PlatformMediaSession
+    : public CanMakeWeakPtr<PlatformMediaSession>
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
-    : public MediaPlaybackTargetClient
+    , public MediaPlaybackTargetClient
 #endif
 #if !RELEASE_LOG_DISABLED
     , private LoggerHelper
@@ -170,7 +172,7 @@
     virtual bool requiresPlaybackTargetRouteMonitoring() const { return false; }
 #endif
 
-    bool activeAudioSessionRequired();
+    bool activeAudioSessionRequired() const;
     bool canProduceAudio() const;
     void canProduceAudioChanged();
 
@@ -189,6 +191,8 @@
     WTFLogChannel& logChannel() const final;
 #endif
 
+    bool canPlayConcurrently(const PlatformMediaSession&) const;
+
 protected:
     PlatformMediaSessionClient& client() const { return m_client; }
 
@@ -253,6 +257,8 @@
 
     virtual bool processingUserGestureForMedia() const = 0;
 
+    virtual bool hasMediaStreamSource() const { return false; }
+
 protected:
     virtual ~PlatformMediaSessionClient() = default;
 };

Modified: trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp (245711 => 245712)


--- trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp	2019-05-23 20:44:06 UTC (rev 245711)
+++ trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp	2019-05-23 20:56:56 UTC (rev 245712)
@@ -79,7 +79,7 @@
 {
     ASSERT(type >= PlatformMediaSession::None && type <= PlatformMediaSession::MediaStreamCapturingAudio);
 
-    return anyOfSessions([type] (PlatformMediaSession& session, size_t) {
+    return anyOfSessions([type] (auto& session) {
         return session.mediaType() == type;
     });
 }
@@ -86,7 +86,7 @@
 
 bool PlatformMediaSessionManager::activeAudioSessionRequired() const
 {
-    return anyOfSessions([] (PlatformMediaSession& session, size_t) {
+    return anyOfSessions([] (auto& session) {
         return session.activeAudioSessionRequired();
     });
 }
@@ -93,7 +93,7 @@
 
 bool PlatformMediaSessionManager::canProduceAudio() const
 {
-    return anyOfSessions([] (PlatformMediaSession& session, size_t) {
+    return anyOfSessions([] (auto& session) {
         return session.canProduceAudio();
     });
 }
@@ -103,7 +103,7 @@
     ASSERT(type >= PlatformMediaSession::None && type <= PlatformMediaSession::MediaStreamCapturingAudio);
 
     int count = 0;
-    for (auto* session : m_sessions) {
+    for (const auto& session : m_sessions) {
         if (session->mediaType() == type)
             ++count;
     }
@@ -116,7 +116,7 @@
     ALWAYS_LOG(LOGIDENTIFIER);
 
     m_interrupted = true;
-    forEachSession([type] (PlatformMediaSession& session, size_t) {
+    forEachSession([type] (auto& session) {
         session.beginInterruption(type);
     });
     updateSessionState();
@@ -127,7 +127,7 @@
     ALWAYS_LOG(LOGIDENTIFIER);
 
     m_interrupted = false;
-    forEachSession([flags] (PlatformMediaSession& session, size_t) {
+    forEachSession([flags] (auto& session) {
         session.endInterruption(flags);
     });
 }
@@ -135,8 +135,7 @@
 void PlatformMediaSessionManager::addSession(PlatformMediaSession& session)
 {
     ALWAYS_LOG(LOGIDENTIFIER, session.logIdentifier());
-    
-    m_sessions.append(&session);
+    m_sessions.append(makeWeakPtr(session));
     if (m_interrupted)
         session.setState(PlatformMediaSession::Interrupted);
 
@@ -156,15 +155,12 @@
 void PlatformMediaSessionManager::removeSession(PlatformMediaSession& session)
 {
     ALWAYS_LOG(LOGIDENTIFIER, session.logIdentifier());
-    
+
     size_t index = m_sessions.find(&session);
     if (index == notFound)
         return;
 
-    if (m_iteratingOverSessions)
-        m_sessions.at(index) = nullptr;
-    else
-        m_sessions.remove(index);
+    m_sessions.remove(index);
 
     if (m_sessions.isEmpty() || std::all_of(m_sessions.begin(), m_sessions.end(), std::logical_not<void>())) {
         m_remoteCommandListener = nullptr;
@@ -233,15 +229,16 @@
     if (m_interrupted)
         endInterruption(PlatformMediaSession::NoFlags);
 
-    forEachSession([&] (PlatformMediaSession& oneSession, size_t) {
-        if (&_oneSession_ == &session)
-            return;
-        if (oneSession.mediaType() == sessionType
-            && restrictions & ConcurrentPlaybackNotPermitted
-            && oneSession.state() == PlatformMediaSession::Playing)
+    if (restrictions & ConcurrentPlaybackNotPermitted) {
+        forEachMatchingSession([&session, sessionType](auto& oneSession) {
+            return &oneSession != &session
+                && oneSession.mediaType() == sessionType
+                && oneSession.state() == PlatformMediaSession::Playing
+                && !oneSession.canPlayConcurrently(session);
+        }, [](auto& oneSession) {
             oneSession.pauseSession();
-    });
-
+        });
+    }
     ALWAYS_LOG(LOGIDENTIFIER, session.logIdentifier(), " returning true");
     return true;
 }
@@ -255,25 +252,27 @@
     
     size_t pausingSessionIndex = notFound;
     size_t lastPlayingSessionIndex = notFound;
-    anyOfSessions([&] (PlatformMediaSession& oneSession, size_t i) {
+    for (size_t i = 0, size = m_sessions.size(); i < size; ++i) {
+        const auto& _oneSession_ = *m_sessions[i];
         if (&_oneSession_ == &session) {
             pausingSessionIndex = i;
-            return false;
+            break;
         }
         if (oneSession.state() == PlatformMediaSession::Playing) {
             lastPlayingSessionIndex = i;
-            return false;
+            break;
         }
-        return oneSession.state() != PlatformMediaSession::Playing;
-    });
+        if (oneSession.state() != PlatformMediaSession::Playing)
+            break;
+    }
     if (lastPlayingSessionIndex == notFound || pausingSessionIndex == notFound)
         return;
     
     if (pausingSessionIndex > lastPlayingSessionIndex)
         return;
-    
+
     m_sessions.remove(pausingSessionIndex);
-    m_sessions.insert(lastPlayingSessionIndex, &session);
+    m_sessions.append(makeWeakPtr(session));
     
     ALWAYS_LOG(LOGIDENTIFIER, "session moved from index ", pausingSessionIndex, " to ", lastPlayingSessionIndex);
 }
@@ -296,7 +295,7 @@
         return;
 
     m_sessions.remove(index);
-    m_sessions.insert(0, &session);
+    m_sessions.insert(0, makeWeakPtr(session));
     if (m_remoteCommandListener)
         m_remoteCommandListener->updateSupportedCommands();
     
@@ -308,40 +307,32 @@
     if (!m_sessions.size())
         return nullptr;
 
-    return m_sessions[0];
+    return m_sessions[0].get();
 }
 
-Vector<PlatformMediaSession*> PlatformMediaSessionManager::currentSessionsMatching(const WTF::Function<bool(const PlatformMediaSession&)>& filter)
+void PlatformMediaSessionManager::applicationWillBecomeInactive()
 {
-    Vector<PlatformMediaSession*> matchingSessions;
-    forEachSession([&] (PlatformMediaSession& session, size_t) {
-        if (filter(session))
-            matchingSessions.append(&session);
-    });
-    return matchingSessions;
-}
-
-void PlatformMediaSessionManager::applicationWillBecomeInactive() const
-{
     ALWAYS_LOG(LOGIDENTIFIER);
 
-    forEachSession([&] (PlatformMediaSession& session, size_t) {
-        if (m_restrictions[session.mediaType()] & InactiveProcessPlaybackRestricted)
-            session.beginInterruption(PlatformMediaSession::ProcessInactive);
+    forEachMatchingSession([&](auto& session) {
+        return m_restrictions[session.mediaType()] & InactiveProcessPlaybackRestricted;
+    }, [](auto& session) {
+        session.beginInterruption(PlatformMediaSession::ProcessInactive);
     });
 }
 
-void PlatformMediaSessionManager::applicationDidBecomeActive() const
+void PlatformMediaSessionManager::applicationDidBecomeActive()
 {
     ALWAYS_LOG(LOGIDENTIFIER);
 
-    forEachSession([&] (PlatformMediaSession& session, size_t) {
-        if (m_restrictions[session.mediaType()] & InactiveProcessPlaybackRestricted)
-            session.endInterruption(PlatformMediaSession::MayResumePlaying);
+    forEachMatchingSession([&](auto& session) {
+        return m_restrictions[session.mediaType()] & InactiveProcessPlaybackRestricted;
+    }, [](auto& session) {
+        session.endInterruption(PlatformMediaSession::MayResumePlaying);
     });
 }
 
-void PlatformMediaSessionManager::applicationDidEnterBackground(bool suspendedUnderLock) const
+void PlatformMediaSessionManager::applicationDidEnterBackground(bool suspendedUnderLock)
 {
     ALWAYS_LOG(LOGIDENTIFIER, "suspendedUnderLock: ", suspendedUnderLock);
 
@@ -350,7 +341,7 @@
 
     m_isApplicationInBackground = true;
 
-    forEachSession([&] (PlatformMediaSession& session, size_t) {
+    forEachSession([&] (auto& session) {
         if (suspendedUnderLock && m_restrictions[session.mediaType()] & SuspendedUnderLockPlaybackRestricted)
             session.beginInterruption(PlatformMediaSession::SuspendedUnderLock);
         else if (m_restrictions[session.mediaType()] & BackgroundProcessPlaybackRestricted)
@@ -358,7 +349,7 @@
     });
 }
 
-void PlatformMediaSessionManager::applicationWillEnterForeground(bool suspendedUnderLock) const
+void PlatformMediaSessionManager::applicationWillEnterForeground(bool suspendedUnderLock)
 {
     ALWAYS_LOG(LOGIDENTIFIER, "suspendedUnderLock: ", suspendedUnderLock);
 
@@ -367,9 +358,10 @@
 
     m_isApplicationInBackground = false;
 
-    forEachSession([&] (PlatformMediaSession& session, size_t) {
-        if ((suspendedUnderLock && m_restrictions[session.mediaType()] & SuspendedUnderLockPlaybackRestricted) || m_restrictions[session.mediaType()] & BackgroundProcessPlaybackRestricted)
-            session.endInterruption(PlatformMediaSession::MayResumePlaying);
+    forEachMatchingSession([&](auto& session) {
+        return (suspendedUnderLock && m_restrictions[session.mediaType()] & SuspendedUnderLockPlaybackRestricted) || m_restrictions[session.mediaType()] & BackgroundProcessPlaybackRestricted;
+    }, [](auto& session) {
+        session.endInterruption(PlatformMediaSession::MayResumePlaying);
     });
 }
 
@@ -438,7 +430,7 @@
     if (m_interrupted)
         return;
 
-    forEachSession([] (PlatformMediaSession& session, size_t) {
+    forEachSession([] (auto& session) {
         session.beginInterruption(PlatformMediaSession::SystemSleep);
     });
 }
@@ -448,7 +440,7 @@
     if (m_interrupted)
         return;
 
-    forEachSession([] (PlatformMediaSession& session, size_t) {
+    forEachSession([] (auto& session) {
         session.endInterruption(PlatformMediaSession::MayResumePlaying);
     });
 }
@@ -458,17 +450,16 @@
     updateSessionState();
 }
 
-void PlatformMediaSessionManager::stopAllMediaPlaybackForDocument(const Document* document)
+void PlatformMediaSessionManager::stopAllMediaPlaybackForDocument(const Document& document)
 {
-    forEachSession([document] (PlatformMediaSession& session, size_t) {
-        if (session.client().hostingDocument() == document)
-            session.pauseSession();
+    forEachDocumentSession(document, [](auto& session) {
+        session.pauseSession();
     });
 }
 
 void PlatformMediaSessionManager::stopAllMediaPlaybackForProcess()
 {
-    forEachSession([] (PlatformMediaSession& session, size_t) {
+    forEachSession([] (auto& session) {
         session.stopSession();
     });
 }
@@ -475,74 +466,75 @@
 
 void PlatformMediaSessionManager::suspendAllMediaPlaybackForDocument(const Document& document)
 {
-    forEachSession([&] (PlatformMediaSession& session, size_t) {
-        if (session.client().hostingDocument() == &document)
-            session.beginInterruption(PlatformMediaSession::PlaybackSuspended);
+    forEachDocumentSession(document, [](auto& session) {
+        session.beginInterruption(PlatformMediaSession::PlaybackSuspended);
     });
 }
 
 void PlatformMediaSessionManager::resumeAllMediaPlaybackForDocument(const Document& document)
 {
-    forEachSession([&] (PlatformMediaSession& session, size_t) {
-        if (session.client().hostingDocument() == &document)
-            session.endInterruption(PlatformMediaSession::MayResumePlaying);
+    forEachDocumentSession(document, [](auto& session) {
+        session.endInterruption(PlatformMediaSession::MayResumePlaying);
     });
 }
 
 void PlatformMediaSessionManager::suspendAllMediaBufferingForDocument(const Document& document)
 {
-    forEachSession([&] (PlatformMediaSession& session, size_t) {
-        if (session.client().hostingDocument() == &document)
-            session.suspendBuffering();
+    forEachDocumentSession(document, [](auto& session) {
+        session.suspendBuffering();
     });
 }
 
 void PlatformMediaSessionManager::resumeAllMediaBufferingForDocument(const Document& document)
 {
-    forEachSession([&] (PlatformMediaSession& session, size_t) {
-        if (session.client().hostingDocument() == &document)
-            session.resumeBuffering();
+    forEachDocumentSession(document, [](auto& session) {
+        session.resumeBuffering();
     });
 }
 
-void PlatformMediaSessionManager::forEachSession(const Function<void(PlatformMediaSession&, size_t)>& predicate) const
+Vector<WeakPtr<PlatformMediaSession>> PlatformMediaSessionManager::sessionsMatching(const WTF::Function<bool(const PlatformMediaSession&)>& filter) const
 {
-    ++m_iteratingOverSessions;
+    Vector<WeakPtr<PlatformMediaSession>> matchingSessions;
+    for (auto& session : m_sessions) {
+        if (filter(*session))
+            matchingSessions.append(session);
+    }
+    return matchingSessions;
+}
 
-    for (size_t i = 0, size = m_sessions.size(); i < size; ++i) {
-        auto session = m_sessions[i];
-        if (!session)
-            continue;
-        predicate(*session, i);
+void PlatformMediaSessionManager::forEachMatchingSession(const Function<bool(const PlatformMediaSession&)>& predicate, const Function<void(PlatformMediaSession&)>& callback)
+{
+    for (auto& session : sessionsMatching(predicate)) {
+        ASSERT(session);
+        if (session)
+            callback(*session);
     }
+}
 
-    --m_iteratingOverSessions;
-    if (!m_iteratingOverSessions)
-        m_sessions.removeAll(nullptr);
+void PlatformMediaSessionManager::forEachDocumentSession(const Document& document, const Function<void(PlatformMediaSession&)>& callback)
+{
+    forEachMatchingSession([&document](auto& session) {
+        return session.client().hostingDocument() == &document;
+    }, [&callback](auto& session) {
+        callback(session);
+    });
 }
 
-PlatformMediaSession* PlatformMediaSessionManager::findSession(const Function<bool(PlatformMediaSession&, size_t)>& predicate) const
+void PlatformMediaSessionManager::forEachSession(const Function<void(PlatformMediaSession&)>& callback)
 {
-    ++m_iteratingOverSessions;
-
-    PlatformMediaSession* foundSession = nullptr;
-    for (size_t i = 0, size = m_sessions.size(); i < size; ++i) {
-        auto session = m_sessions[i];
-        if (!session)
-            continue;
-
-        if (!predicate(*session, i))
-            continue;
-
-        foundSession = session;
-        break;
+    auto sessions = m_sessions;
+    for (auto& session : sessions) {
+        ASSERT(session);
+        if (session)
+            callback(*session);
     }
+}
 
-    --m_iteratingOverSessions;
-    if (!m_iteratingOverSessions)
-        m_sessions.removeAll(nullptr);
-
-    return foundSession;
+bool PlatformMediaSessionManager::anyOfSessions(const Function<bool(const PlatformMediaSession&)>& predicate) const
+{
+    return WTF::anyOf(m_sessions, [&predicate](const auto& session) {
+        return predicate(*session);
+    });
 }
 
 static bool& deactivateAudioSession()

Modified: trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.h (245711 => 245712)


--- trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.h	2019-05-23 20:44:06 UTC (rev 245711)
+++ trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.h	2019-05-23 20:56:56 UTC (rev 245712)
@@ -81,14 +81,14 @@
     WEBCORE_EXPORT virtual void beginInterruption(PlatformMediaSession::InterruptionType);
     WEBCORE_EXPORT void endInterruption(PlatformMediaSession::EndInterruptionFlags);
 
-    WEBCORE_EXPORT void applicationWillBecomeInactive() const;
-    WEBCORE_EXPORT void applicationDidBecomeActive() const;
-    WEBCORE_EXPORT void applicationWillEnterForeground(bool suspendedUnderLock) const;
-    WEBCORE_EXPORT void applicationDidEnterBackground(bool suspendedUnderLock) const;
+    WEBCORE_EXPORT void applicationWillBecomeInactive();
+    WEBCORE_EXPORT void applicationDidBecomeActive();
+    WEBCORE_EXPORT void applicationWillEnterForeground(bool suspendedUnderLock);
+    WEBCORE_EXPORT void applicationDidEnterBackground(bool suspendedUnderLock);
     WEBCORE_EXPORT void processWillSuspend();
     WEBCORE_EXPORT void processDidResume();
 
-    void stopAllMediaPlaybackForDocument(const Document*);
+    void stopAllMediaPlaybackForDocument(const Document&);
     WEBCORE_EXPORT void stopAllMediaPlaybackForProcess();
 
     void suspendAllMediaPlaybackForDocument(const Document&);
@@ -127,10 +127,10 @@
     void setCurrentSession(PlatformMediaSession&);
     PlatformMediaSession* currentSession() const;
 
-    Vector<PlatformMediaSession*> currentSessionsMatching(const WTF::Function<bool(const PlatformMediaSession&)>&);
-
     void sessionIsPlayingToWirelessPlaybackTargetChanged(PlatformMediaSession&);
 
+    void forEachMatchingSession(const Function<bool(const PlatformMediaSession&)>& predicate, const Function<void(PlatformMediaSession&)>& matchingCallback);
+
 protected:
     friend class PlatformMediaSession;
     explicit PlatformMediaSessionManager();
@@ -138,9 +138,9 @@
     void addSession(PlatformMediaSession&);
     virtual void removeSession(PlatformMediaSession&);
 
-    void forEachSession(const Function<void(PlatformMediaSession&, size_t)>&) const;
-    PlatformMediaSession* findSession(const Function<bool(PlatformMediaSession&, size_t)>&) const;
-    bool anyOfSessions(const Function<bool(PlatformMediaSession&, size_t)>& predicate) const { return findSession(predicate); }
+    void forEachSession(const Function<void(PlatformMediaSession&)>&);
+    void forEachDocumentSession(const Document&, const Function<void(PlatformMediaSession&)>&);
+    bool anyOfSessions(const Function<bool(const PlatformMediaSession&)>&) const;
 
     AudioHardwareListener* audioHardwareListener() { return m_audioHardwareListener.get(); }
 
@@ -171,8 +171,10 @@
     void systemWillSleep() override;
     void systemDidWake() override;
 
+    Vector<WeakPtr<PlatformMediaSession>> sessionsMatching(const Function<bool(const PlatformMediaSession&)>&) const;
+
     SessionRestrictions m_restrictions[PlatformMediaSession::MediaStreamCapturingAudio + 1];
-    mutable Vector<PlatformMediaSession*> m_sessions;
+    mutable Vector<WeakPtr<PlatformMediaSession>> m_sessions;
     std::unique_ptr<RemoteCommandListener> m_remoteCommandListener;
     std::unique_ptr<PAL::SystemSleepListener> m_systemSleepListener;
     RefPtr<AudioHardwareListener> m_audioHardwareListener;
@@ -185,7 +187,6 @@
     bool m_interrupted { false };
     mutable bool m_isApplicationInBackground { false };
     bool m_willIgnoreSystemInterruptions { false };
-    mutable int m_iteratingOverSessions { 0 };
     bool m_processIsSuspended { false };
 
 #if USE(AUDIO_SESSION)

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


--- trunk/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.mm	2019-05-23 20:44:06 UTC (rev 245711)
+++ trunk/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.mm	2019-05-23 20:56:56 UTC (rev 245712)
@@ -97,7 +97,7 @@
         return;
 
     bool hasAudibleAudioOrVideoMediaType = false;
-    forEachSession([&hasAudibleAudioOrVideoMediaType] (PlatformMediaSession& session, size_t) mutable {
+    forEachSession([&hasAudibleAudioOrVideoMediaType] (auto& session) mutable {
         auto type = session.mediaType();
         if ((type == PlatformMediaSession::VideoAudio || type == PlatformMediaSession::Audio) && session.canProduceAudio() && session.hasPlayedSinceLastInterruption())
             hasAudibleAudioOrVideoMediaType = true;
@@ -122,7 +122,7 @@
 void MediaSessionManagerCocoa::beginInterruption(PlatformMediaSession::InterruptionType type)
 {
     if (type == PlatformMediaSession::InterruptionType::SystemInterruption) {
-        forEachSession([] (PlatformMediaSession& session, size_t) {
+        forEachSession([] (auto& session) {
             session.clearHasPlayedSinceLastInterruption();
         });
     }

Modified: trunk/Source/WebCore/platform/audio/ios/MediaSessionManagerIOS.mm (245711 => 245712)


--- trunk/Source/WebCore/platform/audio/ios/MediaSessionManagerIOS.mm	2019-05-23 20:44:06 UTC (rev 245711)
+++ trunk/Source/WebCore/platform/audio/ios/MediaSessionManagerIOS.mm	2019-05-23 20:56:56 UTC (rev 245712)
@@ -146,7 +146,7 @@
 void MediaSessionManageriOS::configureWireLessTargetMonitoring()
 {
 #if HAVE(MEDIA_PLAYER) && !PLATFORM(WATCHOS)
-    bool requiresMonitoring = anyOfSessions([] (PlatformMediaSession& session, size_t) {
+    bool requiresMonitoring = anyOfSessions([] (auto& session) {
         return session.requiresPlaybackTargetRouteMonitoring();
     });
 
@@ -187,7 +187,7 @@
     bool haveTargets = [m_objcObserver hasWirelessTargetsAvailable];
     ALWAYS_LOG(LOGIDENTIFIER, haveTargets);
 
-    forEachSession([haveTargets] (PlatformMediaSession& session, size_t) {
+    forEachSession([haveTargets] (auto& session) {
         session.externalOutputDeviceAvailableDidChange(haveTargets);
     });
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to