<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[277361] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/277361">277361</a></dd>
<dt>Author</dt> <dd>youenn@apple.com</dd>
<dt>Date</dt> <dd>2021-05-12 01:05:19 -0700 (Wed, 12 May 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>Enumerate AVCaptureDevice list in a background thread
https://bugs.webkit.org/show_bug.cgi?id=225643
<rdar://problem/77820002>

Reviewed by Eric Carlson.

Enumerate AVCaptureDevice in a background queue asynchronously.
Delay getUserMedia and enumerateDevices until this is completed.

Update RealtimeMediaSourceCenter accordingly and introduce RealtimeMediaSourceCenter::enumerateDevices for that purpose.
Replace getCaptureDevices by computeCaptureDevices to do the async computation.
Continue using captureDevices() getters.

Manually tested.

* platform/mediastream/CaptureDevice.h:
(WebCore::CaptureDevice::CaptureDevice):
(WebCore::CaptureDevice::isolatedCopy):
* platform/mediastream/CaptureDeviceManager.h:
* platform/mediastream/RealtimeMediaSourceCenter.cpp:
(WebCore::RealtimeMediaSourceCenter::getMediaStreamDevices):
(WebCore::RealtimeMediaSourceCenter::enumerateDevices):
(WebCore::RealtimeMediaSourceCenter::validateRequestConstraints):
(WebCore::RealtimeMediaSourceCenter::validateRequestConstraintsAfterEnumeration):
* platform/mediastream/RealtimeMediaSourceCenter.h:
* platform/mediastream/RealtimeMediaSourceFactory.h:
(WebCore::AudioCaptureFactory::computeSpeakerDevices const):
* platform/mediastream/ios/AVAudioSessionCaptureDevice.mm:
(WebCore::AVAudioSessionCaptureDevice::AVAudioSessionCaptureDevice):
* platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.h:
* platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm:
(WebCore::AVAudioSessionCaptureDeviceManager::scheduleUpdateCaptureDevices):
(WebCore::AVAudioSessionCaptureDeviceManager::computeCaptureDevices):
* platform/mediastream/mac/AVCaptureDeviceManager.h:
* platform/mediastream/mac/AVCaptureDeviceManager.mm:
(WebCore::AVCaptureDeviceManager::computeCaptureDevices):
(WebCore::AVCaptureDeviceManager::captureDevices):
(WebCore::AVCaptureDeviceManager::updateCachedAVCaptureDevices):
(WebCore::AVCaptureDeviceManager::retrieveCaptureDevices):
(WebCore::AVCaptureDeviceManager::refreshCaptureDevices):
(WebCore::AVCaptureDeviceManager::AVCaptureDeviceManager):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamCaptureDeviceh">trunk/Source/WebCore/platform/mediastream/CaptureDevice.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamCaptureDeviceManagerh">trunk/Source/WebCore/platform/mediastream/CaptureDeviceManager.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamRealtimeMediaSourceCentercpp">trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamRealtimeMediaSourceCenterh">trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamRealtimeMediaSourceFactoryh">trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceFactory.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamiosAVAudioSessionCaptureDevicemm">trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDevice.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamiosAVAudioSessionCaptureDeviceManagerh">trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamiosAVAudioSessionCaptureDeviceManagermm">trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacAVCaptureDeviceManagerh">trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacAVCaptureDeviceManagermm">trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (277360 => 277361)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2021-05-12 07:56:39 UTC (rev 277360)
+++ trunk/Source/WebCore/ChangeLog      2021-05-12 08:05:19 UTC (rev 277361)
</span><span class="lines">@@ -1,3 +1,47 @@
</span><ins>+2021-05-12  Youenn Fablet  <youenn@apple.com>
+
+        Enumerate AVCaptureDevice list in a background thread
+        https://bugs.webkit.org/show_bug.cgi?id=225643
+        <rdar://problem/77820002>
+
+        Reviewed by Eric Carlson.
+
+        Enumerate AVCaptureDevice in a background queue asynchronously.
+        Delay getUserMedia and enumerateDevices until this is completed.
+
+        Update RealtimeMediaSourceCenter accordingly and introduce RealtimeMediaSourceCenter::enumerateDevices for that purpose.
+        Replace getCaptureDevices by computeCaptureDevices to do the async computation.
+        Continue using captureDevices() getters.
+
+        Manually tested.
+
+        * platform/mediastream/CaptureDevice.h:
+        (WebCore::CaptureDevice::CaptureDevice):
+        (WebCore::CaptureDevice::isolatedCopy):
+        * platform/mediastream/CaptureDeviceManager.h:
+        * platform/mediastream/RealtimeMediaSourceCenter.cpp:
+        (WebCore::RealtimeMediaSourceCenter::getMediaStreamDevices):
+        (WebCore::RealtimeMediaSourceCenter::enumerateDevices):
+        (WebCore::RealtimeMediaSourceCenter::validateRequestConstraints):
+        (WebCore::RealtimeMediaSourceCenter::validateRequestConstraintsAfterEnumeration):
+        * platform/mediastream/RealtimeMediaSourceCenter.h:
+        * platform/mediastream/RealtimeMediaSourceFactory.h:
+        (WebCore::AudioCaptureFactory::computeSpeakerDevices const):
+        * platform/mediastream/ios/AVAudioSessionCaptureDevice.mm:
+        (WebCore::AVAudioSessionCaptureDevice::AVAudioSessionCaptureDevice):
+        * platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.h:
+        * platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm:
+        (WebCore::AVAudioSessionCaptureDeviceManager::scheduleUpdateCaptureDevices):
+        (WebCore::AVAudioSessionCaptureDeviceManager::computeCaptureDevices):
+        * platform/mediastream/mac/AVCaptureDeviceManager.h:
+        * platform/mediastream/mac/AVCaptureDeviceManager.mm:
+        (WebCore::AVCaptureDeviceManager::computeCaptureDevices):
+        (WebCore::AVCaptureDeviceManager::captureDevices):
+        (WebCore::AVCaptureDeviceManager::updateCachedAVCaptureDevices):
+        (WebCore::AVCaptureDeviceManager::retrieveCaptureDevices):
+        (WebCore::AVCaptureDeviceManager::refreshCaptureDevices):
+        (WebCore::AVCaptureDeviceManager::AVCaptureDeviceManager):
+
</ins><span class="cx"> 2021-05-11  Cameron McCormack  <heycam@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Include reasons for compositing in showLayerTree output
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamCaptureDeviceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/CaptureDevice.h (277360 => 277361)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/CaptureDevice.h        2021-05-12 07:56:39 UTC (rev 277360)
+++ trunk/Source/WebCore/platform/mediastream/CaptureDevice.h   2021-05-12 08:05:19 UTC (rev 277361)
</span><span class="lines">@@ -33,11 +33,14 @@
</span><span class="cx"> public:
</span><span class="cx">     enum class DeviceType { Unknown, Microphone, Speaker, Camera, Screen, Window };
</span><span class="cx"> 
</span><del>-    CaptureDevice(const String& persistentId, DeviceType type, const String& label, const String& groupId = emptyString())
</del><ins>+    CaptureDevice(const String& persistentId, DeviceType type, const String& label, const String& groupId = emptyString(), bool isEnabled = false, bool isDefault = false, bool isMock = false)
</ins><span class="cx">         : m_persistentId(persistentId)
</span><span class="cx">         , m_type(type)
</span><span class="cx">         , m_label(label)
</span><span class="cx">         , m_groupId(groupId)
</span><ins>+        , m_enabled(isEnabled)
+        , m_default(isDefault)
+        , m_isMockDevice(isMock)
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -71,6 +74,8 @@
</span><span class="cx"> 
</span><span class="cx">     explicit operator bool() const { return m_type != DeviceType::Unknown; }
</span><span class="cx"> 
</span><ins>+    CaptureDevice isolatedCopy() &&;
+
</ins><span class="cx"> #if ENABLE(MEDIA_STREAM)
</span><span class="cx">     template<class Encoder>
</span><span class="cx">     void encode(Encoder& encoder) const
</span><span class="lines">@@ -160,6 +165,19 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline CaptureDevice CaptureDevice::isolatedCopy() &&
+{
+    return {
+        WTFMove(m_persistentId).isolatedCopy(),
+        m_type,
+        WTFMove(m_label).isolatedCopy(),
+        WTFMove(m_groupId).isolatedCopy(),
+        m_enabled,
+        m_default,
+        m_isMockDevice
+    };
+}
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MEDIA_STREAM)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamCaptureDeviceManagerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/CaptureDeviceManager.h (277360 => 277361)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/CaptureDeviceManager.h 2021-05-12 07:56:39 UTC (rev 277360)
+++ trunk/Source/WebCore/platform/mediastream/CaptureDeviceManager.h    2021-05-12 08:05:19 UTC (rev 277361)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> class WEBCORE_EXPORT CaptureDeviceManager {
</span><span class="cx"> public:
</span><span class="cx">     virtual const Vector<CaptureDevice>& captureDevices() = 0;
</span><del>-    virtual void getCaptureDevices(CompletionHandler<void(Vector<CaptureDevice>&&)>&& callback) { callback(copyToVector(captureDevices())); };
</del><ins>+    virtual void computeCaptureDevices(CompletionHandler<void()>&& callback) { callback(); }
</ins><span class="cx">     virtual Optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType, const String&) { return WTF::nullopt; }
</span><span class="cx"> 
</span><span class="cx"> protected:
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamRealtimeMediaSourceCentercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp (277360 => 277361)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp  2021-05-12 07:56:39 UTC (rev 277360)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp     2021-05-12 08:05:19 UTC (rev 277361)
</span><span class="lines">@@ -38,6 +38,7 @@
</span><span class="cx"> #include "CaptureDeviceManager.h"
</span><span class="cx"> #include "Logging.h"
</span><span class="cx"> #include "MediaStreamPrivate.h"
</span><ins>+#include <wtf/CallbackAggregator.h>
</ins><span class="cx"> #include <wtf/SHA1.h>
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="lines">@@ -119,46 +120,16 @@
</span><span class="cx"> 
</span><span class="cx"> void RealtimeMediaSourceCenter::getMediaStreamDevices(CompletionHandler<void(Vector<CaptureDevice>&&)>&& completion)
</span><span class="cx"> {
</span><del>-    class CaptureDeviceAccumulator : public RefCounted<CaptureDeviceAccumulator> {
-    public:
-        static Ref<CaptureDeviceAccumulator> create(CompletionHandler<void(Vector<CaptureDevice>&&)>&& completion)
-        {
-            return adoptRef(*new CaptureDeviceAccumulator(WTFMove(completion)));
-        }
</del><ins>+    enumerateDevices(true, true, true, true, [this, completion = WTFMove(completion)]() mutable {
+        Vector<CaptureDevice> results;
</ins><span class="cx"> 
</span><del>-        ~CaptureDeviceAccumulator()
-        {
-            m_completionHandler(WTFMove(m_results));
-        }
</del><ins>+        results.appendVector(audioCaptureFactory().audioCaptureDeviceManager().captureDevices());
+        results.appendVector(videoCaptureFactory().videoCaptureDeviceManager().captureDevices());
+        results.appendVector(displayCaptureFactory().displayCaptureDeviceManager().captureDevices());
+        results.appendVector(audioCaptureFactory().speakerDevices());
</ins><span class="cx"> 
</span><del>-        CompletionHandler<void(Vector<CaptureDevice>&&)> accumulate()
-        {
-            return [this, protectedThis = makeRef(*this)] (Vector<CaptureDevice>&& result) {
-                m_results.appendVector(WTFMove(result));
-            };
-        }
-
-    private:
-        explicit CaptureDeviceAccumulator(CompletionHandler<void(Vector<CaptureDevice>&&)>&& completion)
-            : m_completionHandler(WTFMove(completion))
-        {
-        }
-
-        CompletionHandler<void(Vector<CaptureDevice>&&)> m_completionHandler;
-        Vector<CaptureDevice> m_results;
-    };
-
-    auto accumulator = CaptureDeviceAccumulator::create([completion = WTFMove(completion)] (auto&& devices) mutable {
-        devices.removeAllMatching([] (auto& captureDevice) {
-            return !captureDevice.enabled();
-        });
-        completion(WTFMove(devices));
</del><ins>+        completion(WTFMove(results));
</ins><span class="cx">     });
</span><del>-
-    audioCaptureFactory().audioCaptureDeviceManager().getCaptureDevices(accumulator->accumulate());
-    videoCaptureFactory().videoCaptureDeviceManager().getCaptureDevices(accumulator->accumulate());
-    displayCaptureFactory().displayCaptureDeviceManager().getCaptureDevices(accumulator->accumulate());
-    audioCaptureFactory().getSpeakerDevices(accumulator->accumulate());
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void addStringToSHA1(SHA1& sha1, const String& string)
</span><span class="lines">@@ -274,8 +245,32 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void RealtimeMediaSourceCenter::enumerateDevices(bool shouldEnumerateCamera, bool shouldEnumerateDisplay, bool shouldEnumerateMicrophone, bool shouldEnumerateSpeakers, CompletionHandler<void()>&& callback)
+{
+    auto callbackAggregator = CallbackAggregator::create(WTFMove(callback));
+    if (shouldEnumerateCamera)
+        videoCaptureFactory().videoCaptureDeviceManager().computeCaptureDevices([callbackAggregator] { });
+    if (shouldEnumerateDisplay)
+        displayCaptureFactory().displayCaptureDeviceManager().computeCaptureDevices([callbackAggregator] { });
+    if (shouldEnumerateMicrophone)
+        audioCaptureFactory().audioCaptureDeviceManager().computeCaptureDevices([callbackAggregator] { });
+    if (shouldEnumerateSpeakers)
+        audioCaptureFactory().computeSpeakerDevices([callbackAggregator] { });
+}
+
</ins><span class="cx"> void RealtimeMediaSourceCenter::validateRequestConstraints(ValidConstraintsHandler&& validHandler, InvalidConstraintsHandler&& invalidHandler, const MediaStreamRequest& request, String&& deviceIdentifierHashSalt)
</span><span class="cx"> {
</span><ins>+    bool shouldEnumerateCamera = request.videoConstraints.isValid;
+    bool shouldEnumerateDisplay = request.type == MediaStreamRequest::Type::DisplayMedia;
+    bool shouldEnumerateMicrophone = request.audioConstraints.isValid;
+    bool shouldEnumerateSpeakers = false;
+    enumerateDevices(shouldEnumerateCamera, shouldEnumerateDisplay, shouldEnumerateMicrophone, shouldEnumerateSpeakers, [this, validHandler = WTFMove(validHandler), invalidHandler = WTFMove(invalidHandler), request, deviceIdentifierHashSalt = WTFMove(deviceIdentifierHashSalt)]() mutable {
+        validateRequestConstraintsAfterEnumeration(WTFMove(validHandler), WTFMove(invalidHandler), request, WTFMove(deviceIdentifierHashSalt));
+    });
+}
+
+void RealtimeMediaSourceCenter::validateRequestConstraintsAfterEnumeration(ValidConstraintsHandler&& validHandler, InvalidConstraintsHandler&& invalidHandler, const MediaStreamRequest& request, String&& deviceIdentifierHashSalt)
+{
</ins><span class="cx">     struct {
</span><span class="cx">         bool operator()(const DeviceInfo& a, const DeviceInfo& b)
</span><span class="cx">         {
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamRealtimeMediaSourceCenterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h (277360 => 277361)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h    2021-05-12 07:56:39 UTC (rev 277360)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h       2021-05-12 08:05:19 UTC (rev 277361)
</span><span class="lines">@@ -115,6 +115,8 @@
</span><span class="cx"> 
</span><span class="cx">     void getDisplayMediaDevices(const MediaStreamRequest&, Vector<DeviceInfo>&, String&);
</span><span class="cx">     void getUserMediaDevices(const MediaStreamRequest&, String&&, Vector<DeviceInfo>& audioDevices, Vector<DeviceInfo>& videoDevices, String&);
</span><ins>+    void validateRequestConstraintsAfterEnumeration(ValidConstraintsHandler&&, InvalidConstraintsHandler&&, const MediaStreamRequest&, String&&);
+    void enumerateDevices(bool shouldEnumerateCamera, bool shouldEnumerateDisplay, bool shouldEnumerateMicrophone, bool shouldEnumerateSpeakers, CompletionHandler<void()>&&);
</ins><span class="cx"> 
</span><span class="cx">     RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamRealtimeMediaSourceFactoryh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceFactory.h (277360 => 277361)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceFactory.h   2021-05-12 07:56:39 UTC (rev 277360)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceFactory.h      2021-05-12 08:05:19 UTC (rev 277361)
</span><span class="lines">@@ -63,7 +63,7 @@
</span><span class="cx">     virtual CaptureSourceOrError createAudioCaptureSource(const CaptureDevice&, String&&, const MediaConstraints*) = 0;
</span><span class="cx">     virtual CaptureDeviceManager& audioCaptureDeviceManager() = 0;
</span><span class="cx">     virtual const Vector<CaptureDevice>& speakerDevices() const = 0;
</span><del>-    virtual void getSpeakerDevices(CompletionHandler<void(Vector<CaptureDevice>&&)>&& completion) const { completion(copyToVector(speakerDevices())); }
</del><ins>+    virtual void computeSpeakerDevices(CompletionHandler<void()>&& callback) const { callback(); }
</ins><span class="cx"> 
</span><span class="cx">     class ExtensiveObserver : public CanMakeWeakPtr<ExtensiveObserver> { };
</span><span class="cx">     virtual void addExtensiveObserver(ExtensiveObserver&) { };
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamiosAVAudioSessionCaptureDevicemm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDevice.mm (277360 => 277361)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDevice.mm     2021-05-12 07:56:39 UTC (rev 277360)
+++ trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDevice.mm        2021-05-12 08:05:19 UTC (rev 277361)
</span><span class="lines">@@ -45,11 +45,8 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> AVAudioSessionCaptureDevice::AVAudioSessionCaptureDevice(const String& persistentId, DeviceType type, const String& label, const String& groupId, bool isEnabled, bool isDefault, bool isMock)
</span><del>-    : CaptureDevice(persistentId, type, label, groupId)
</del><ins>+    : CaptureDevice(persistentId, type, label, groupId, isEnabled, isDefault, isMock)
</ins><span class="cx"> {
</span><del>-    setEnabled(isEnabled);
-    setIsDefault(isDefault);
-    setIsMockDevice(isMock);
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> AVAudioSessionCaptureDevice AVAudioSessionCaptureDevice::isolatedCopy() &&
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamiosAVAudioSessionCaptureDeviceManagerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.h (277360 => 277361)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.h       2021-05-12 07:56:39 UTC (rev 277360)
+++ trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.h  2021-05-12 08:05:19 UTC (rev 277361)
</span><span class="lines">@@ -47,7 +47,7 @@
</span><span class="cx">     static AVAudioSessionCaptureDeviceManager& singleton();
</span><span class="cx"> 
</span><span class="cx">     const Vector<CaptureDevice>& captureDevices() final;
</span><del>-    void getCaptureDevices(CompletionHandler<void(Vector<CaptureDevice>&&)>&&) final;
</del><ins>+    void computeCaptureDevices(CompletionHandler<void()>&&) final;
</ins><span class="cx">     const Vector<CaptureDevice>& speakerDevices() const { return m_speakerDevices; }
</span><span class="cx">     Optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType, const String&);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamiosAVAudioSessionCaptureDeviceManagermm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm (277360 => 277361)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm      2021-05-12 07:56:39 UTC (rev 277360)
+++ trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm 2021-05-12 08:05:19 UTC (rev 277361)
</span><span class="lines">@@ -146,7 +146,7 @@
</span><span class="cx"> 
</span><span class="cx"> void AVAudioSessionCaptureDeviceManager::scheduleUpdateCaptureDevices()
</span><span class="cx"> {
</span><del>-    getCaptureDevices([] (auto) { });
</del><ins>+    computeCaptureDevices([] { });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices()
</span><span class="lines">@@ -166,7 +166,7 @@
</span><span class="cx">     setAudioCaptureDevices(WTFMove(newAudioDevices).isolatedCopy());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void AVAudioSessionCaptureDeviceManager::getCaptureDevices(CompletionHandler<void(Vector<CaptureDevice>&&)>&& completion)
</del><ins>+void AVAudioSessionCaptureDeviceManager::computeCaptureDevices(CompletionHandler<void()>&& completion)
</ins><span class="cx"> {
</span><span class="cx">     if (m_audioSessionState == AudioSessionState::Inactive) {
</span><span class="cx">         m_audioSessionState = AudioSessionState::Active;
</span><span class="lines">@@ -180,7 +180,7 @@
</span><span class="cx">         auto newAudioDevices = retrieveAudioSessionCaptureDevices();
</span><span class="cx">         callOnWebThreadOrDispatchAsyncOnMainThread(makeBlockPtr([this, completion = WTFMove(completion), newAudioDevices = WTFMove(newAudioDevices).isolatedCopy()] () mutable {
</span><span class="cx">             setAudioCaptureDevices(WTFMove(newAudioDevices));
</span><del>-            completion(copyToVector(*m_devices));
</del><ins>+            completion();
</ins><span class="cx">         }).get());
</span><span class="cx">     });
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacAVCaptureDeviceManagerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.h (277360 => 277361)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.h   2021-05-12 07:56:39 UTC (rev 277360)
+++ trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.h      2021-05-12 08:05:19 UTC (rev 277361)
</span><span class="lines">@@ -33,6 +33,7 @@
</span><span class="cx"> #include "RealtimeMediaSourceSupportedConstraints.h"
</span><span class="cx"> #include <wtf/NeverDestroyed.h>
</span><span class="cx"> #include <wtf/RetainPtr.h>
</span><ins>+#include <wtf/WorkQueue.h>
</ins><span class="cx"> #include <wtf/text/WTFString.h>
</span><span class="cx"> 
</span><span class="cx"> OBJC_CLASS AVCaptureDevice;
</span><span class="lines">@@ -47,11 +48,9 @@
</span><span class="cx"> class AVCaptureDeviceManager final : public CaptureDeviceManager {
</span><span class="cx">     friend class NeverDestroyed<AVCaptureDeviceManager>;
</span><span class="cx"> public:
</span><del>-    const Vector<CaptureDevice>& captureDevices() final;
-
</del><span class="cx">     static AVCaptureDeviceManager& singleton();
</span><span class="cx"> 
</span><del>-    void refreshCaptureDevices();
</del><ins>+    void refreshCaptureDevices(CompletionHandler<void()>&& = [] { });
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     static bool isAvailable();
</span><span class="lines">@@ -59,15 +58,19 @@
</span><span class="cx">     AVCaptureDeviceManager();
</span><span class="cx">     ~AVCaptureDeviceManager() final;
</span><span class="cx"> 
</span><ins>+    void computeCaptureDevices(CompletionHandler<void()>&&) final;
+    const Vector<CaptureDevice>& captureDevices() final;
+
</ins><span class="cx">     void registerForDeviceNotifications();
</span><del>-    Vector<CaptureDevice>& captureDevicesInternal();
</del><span class="cx">     void updateCachedAVCaptureDevices();
</span><del>-    bool isMatchingExistingCaptureDevice(AVCaptureDevice*);
</del><ins>+    Vector<CaptureDevice> retrieveCaptureDevices();
</ins><span class="cx"> 
</span><span class="cx">     RetainPtr<WebCoreAVCaptureDeviceManagerObserver> m_objcObserver;
</span><span class="cx">     Vector<CaptureDevice> m_devices;
</span><span class="cx">     RetainPtr<NSMutableArray> m_avCaptureDevices;
</span><del>-    bool m_notifyWhenDeviceListChanges { false };
</del><ins>+    bool m_isInitialized { false };
+
+    Ref<WorkQueue> m_dispatchQueue;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacAVCaptureDeviceManagermm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.mm (277360 => 277361)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.mm  2021-05-12 07:56:39 UTC (rev 277360)
+++ trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.mm     2021-05-12 08:05:19 UTC (rev 277361)
</span><span class="lines">@@ -59,25 +59,23 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-
-Vector<CaptureDevice>& AVCaptureDeviceManager::captureDevicesInternal()
</del><ins>+void AVCaptureDeviceManager::computeCaptureDevices(CompletionHandler<void()>&& callback)
</ins><span class="cx"> {
</span><del>-    if (!isAvailable())
-        return m_devices;
-
-    static bool firstTime = true;
-    if (firstTime) {
-        firstTime = false;
-        refreshCaptureDevices();
-        m_notifyWhenDeviceListChanges = true;
</del><ins>+    if (!m_isInitialized) {
+        refreshCaptureDevices([this, callback = WTFMove(callback)]() mutable {
+            m_isInitialized = true;
+            callback();
+        });
+        return;
</ins><span class="cx">     }
</span><del>-
-    return m_devices;
</del><ins>+    callback();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> const Vector<CaptureDevice>& AVCaptureDeviceManager::captureDevices()
</span><span class="cx"> {
</span><del>-    return captureDevicesInternal();
</del><ins>+    ASSERT(m_isInitialized);
+    RELEASE_LOG_ERROR_IF(!m_isInitialized, WebRTC, "Retrieving AVCaptureDeviceManager list before initialization");
+    return m_devices;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline static bool deviceIsAvailable(AVCaptureDevice *device)
</span><span class="lines">@@ -95,6 +93,7 @@
</span><span class="cx"> 
</span><span class="cx"> void AVCaptureDeviceManager::updateCachedAVCaptureDevices()
</span><span class="cx"> {
</span><ins>+    ASSERT(!isMainThread());
</ins><span class="cx">     auto* currentDevices = [PAL::getAVCaptureDeviceClass() devices];
</span><span class="cx">     auto changedDevices = adoptNS([[NSMutableArray alloc] init]);
</span><span class="cx">     for (AVCaptureDevice *cachedDevice in m_avCaptureDevices.get()) {
</span><span class="lines">@@ -129,29 +128,17 @@
</span><span class="cx">     return captureDevice;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool AVCaptureDeviceManager::isMatchingExistingCaptureDevice(AVCaptureDevice *device)
-{
-    auto existingCaptureDevice = captureDeviceFromPersistentID(device.uniqueID);
-    if (!existingCaptureDevice)
-        return false;
-
-    return deviceIsAvailable(device) == existingCaptureDevice.enabled();
-}
-
-static inline bool isDefaultVideoCaptureDeviceFirst(const Vector<CaptureDevice>& devices, const String& defaultDeviceID)
-{
-    if (devices.isEmpty())
-        return false;
-    return devices[0].persistentId() == defaultDeviceID;
-}
-
</del><span class="cx"> static inline bool isVideoDevice(AVCaptureDevice *device)
</span><span class="cx"> {
</span><span class="cx">     return [device hasMediaType:AVMediaTypeVideo] || [device hasMediaType:AVMediaTypeMuxed];
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void AVCaptureDeviceManager::refreshCaptureDevices()
</del><ins>+Vector<CaptureDevice> AVCaptureDeviceManager::retrieveCaptureDevices()
</ins><span class="cx"> {
</span><ins>+    ASSERT(!isMainThread());
+    if (!isAvailable())
+        return { };
+
</ins><span class="cx">     if (!m_avCaptureDevices) {
</span><span class="cx">         m_avCaptureDevices = adoptNS([[NSMutableArray alloc] init]);
</span><span class="cx">         registerForDeviceNotifications();
</span><span class="lines">@@ -178,31 +165,40 @@
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    bool deviceHasChanged = false;
</del><span class="cx">     if (defaultVideoDevice) {
</span><del>-        deviceList.append(toCaptureDevice(defaultVideoDevice));
-        deviceHasChanged = !isDefaultVideoCaptureDeviceFirst(captureDevices(), defaultVideoDevice.uniqueID);
</del><ins>+        auto device = toCaptureDevice(defaultVideoDevice);
+        device.setIsDefault(true);
+        deviceList.append(WTFMove(device));
</ins><span class="cx">     }
</span><span class="cx">     for (AVCaptureDevice *platformDevice in currentDevices) {
</span><del>-        if (!isVideoDevice(platformDevice))
-            continue;
-
-        if (!deviceHasChanged && !isMatchingExistingCaptureDevice(platformDevice))
-            deviceHasChanged = true;
-
-        if (platformDevice.uniqueID == defaultVideoDevice.uniqueID)
-            continue;
-
-        deviceList.append(toCaptureDevice(platformDevice));
</del><ins>+        if (isVideoDevice(platformDevice) && platformDevice.uniqueID != defaultVideoDevice.uniqueID)
+            deviceList.append(toCaptureDevice(platformDevice));
</ins><span class="cx">     }
</span><ins>+    return deviceList;
+}
</ins><span class="cx"> 
</span><del>-    if (deviceHasChanged || m_devices.size() != deviceList.size()) {
-        deviceHasChanged = true;
-        m_devices = WTFMove(deviceList);
-    }
</del><ins>+void AVCaptureDeviceManager::refreshCaptureDevices(CompletionHandler<void()>&& callback)
+{
+    m_dispatchQueue->dispatch([this, callback = WTFMove(callback)]() mutable {
+        RunLoop::main().dispatch([this, callback = WTFMove(callback), deviceList = retrieveCaptureDevices().isolatedCopy()]() mutable {            
+            bool deviceHasChanged = m_devices.size() != deviceList.size();
+            if (!deviceHasChanged) {
+                for (size_t cptr = 0; cptr < deviceList.size(); ++cptr) {
+                    if (m_devices[cptr].persistentId() != deviceList[cptr].persistentId() || m_devices[cptr].enabled() != deviceList[cptr].enabled()) {
+                        deviceHasChanged = true;
+                        break;
+                    }
+                }
+            }
</ins><span class="cx"> 
</span><del>-    if (m_notifyWhenDeviceListChanges && deviceHasChanged)
-        deviceChanged();
</del><ins>+            if (deviceHasChanged) {
+                m_devices = WTFMove(deviceList);
+                if (m_isInitialized)
+                    deviceChanged();
+            }
+            callback();
+        });
+    });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool AVCaptureDeviceManager::isAvailable()
</span><span class="lines">@@ -218,6 +214,7 @@
</span><span class="cx"> 
</span><span class="cx"> AVCaptureDeviceManager::AVCaptureDeviceManager()
</span><span class="cx">     : m_objcObserver(adoptNS([[WebCoreAVCaptureDeviceManagerObserver alloc] initWithCallback: this]))
</span><ins>+    , m_dispatchQueue(WorkQueue::create("com.apple.WebKit.AVCaptureDeviceManager"))
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>