<!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>[269688] 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/269688">269688</a></dd>
<dt>Author</dt> <dd>eric.carlson@apple.com</dd>
<dt>Date</dt> <dd>2020-11-11 10:06:46 -0800 (Wed, 11 Nov 2020)</dd>
</dl>

<h3>Log Message</h3>
<pre>USB microphone not recognized iOS Safari
https://bugs.webkit.org/show_bug.cgi?id=211192
<rdar://problem/62607313>

Reviewed by Youenn Fablet.

Source/WebCore:

Testing requires hardware, tested manually.

* platform/mediastream/CaptureDevice.h: Add concept of default device.
(WebCore::CaptureDevice::isDefault const):
(WebCore::CaptureDevice::setIsDefault):
(WebCore::CaptureDevice::encode const):
(WebCore::CaptureDevice::decode):

* platform/mediastream/ios/AVAudioSessionCaptureDevice.h: Don't retain port
description, it is never used.
* platform/mediastream/ios/AVAudioSessionCaptureDevice.mm:
(WebCore::AVAudioSessionCaptureDevice::create): Add default input parameter.
(WebCore::AVAudioSessionCaptureDevice::AVAudioSessionCaptureDevice): Set enabled
and default attributes.

* platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.h:
* platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm:
(-[WebAVAudioSessionAvailableInputsListener initWithCallback:audioSession:]): Take
parent object and audio session. Listen for session route change notification.
(-[WebAVAudioSessionAvailableInputsListener invalidate]):
(-[WebAVAudioSessionAvailableInputsListener routeDidChange:]):
(WebCore::AVAudioSessionCaptureDeviceManager::AVAudioSessionCaptureDeviceManager):
Allocate and use an auxiliary audio session because it isn't possible to enumerate
all audio inputs without one.
(WebCore::AVAudioSessionCaptureDeviceManager::audioSessionDeviceWithUID): No need
to call refreshAudioCaptureDevices, audioSessionCaptureDevices does it if necessary.
(WebCore::AVAudioSessionCaptureDeviceManager::scheduleUpdateCaptureDevices): New,
refresh devices on a task queue because we frequently get more than one notification
when a route changes.
(WebCore::AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices): Sort devices
so the default is always first. Only call deviceChanged when something actually changes.
(-[WebAVAudioSessionAvailableInputsListener initWithCallback:]): Deleted.
(-[WebAVAudioSessionAvailableInputsListener observeValueForKeyPath:ofObject:change:context:]): Deleted.

* platform/mediastream/mac/CoreAudioCaptureDevice.cpp:
(WebCore::getDeviceInfo): Deal with input and output devices. Translate the data
source name if possible.
(WebCore::CoreAudioCaptureDevice::create):
(WebCore::CoreAudioCaptureDevice::CoreAudioCaptureDevice): Set new `default` attribute.
(WebCore::CoreAudioCaptureDevice::defaultDevice): New.
* platform/mediastream/mac/CoreAudioCaptureDevice.h:

* platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp:
(WebCore::CoreAudioCaptureDeviceManager::scheduleUpdateCaptureDevices): New, coalesce
calls to refreshAudioCaptureDevices.
(WebCore::CoreAudioCaptureDeviceManager::coreAudioCaptureDevices):
(WebCore::computeAudioDeviceList): No need to check for the default device explicitly.
(WebCore::CoreAudioCaptureDeviceManager::refreshAudioCaptureDevices):
(WebCore::getDefaultCaptureInputDevice): Deleted.
(WebCore::getDefaultCaptureOutputDevice): Deleted.
* platform/mediastream/mac/CoreAudioCaptureDeviceManager.h:

Source/WebCore/PAL:

* pal/spi/cocoa/AVFoundationSPI.h: Declare +[AVAudioSession initAuxiliarySession].</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorePALChangeLog">trunk/Source/WebCore/PAL/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorePALpalspicocoaAVFoundationSPIh">trunk/Source/WebCore/PAL/pal/spi/cocoa/AVFoundationSPI.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamCaptureDeviceh">trunk/Source/WebCore/platform/mediastream/CaptureDevice.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamiosAVAudioSessionCaptureDeviceh">trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDevice.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="#trunkSourceWebCoreplatformmediastreammacCoreAudioCaptureDevicecpp">trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDevice.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacCoreAudioCaptureDeviceh">trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDevice.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacCoreAudioCaptureDeviceManagercpp">trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacCoreAudioCaptureDeviceManagerh">trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDeviceManager.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (269687 => 269688)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2020-11-11 17:23:11 UTC (rev 269687)
+++ trunk/Source/WebCore/ChangeLog      2020-11-11 18:06:46 UTC (rev 269688)
</span><span class="lines">@@ -1,3 +1,63 @@
</span><ins>+2020-11-11  Eric Carlson  <eric.carlson@apple.com>
+
+        USB microphone not recognized iOS Safari
+        https://bugs.webkit.org/show_bug.cgi?id=211192
+        <rdar://problem/62607313>
+
+        Reviewed by Youenn Fablet.
+
+        Testing requires hardware, tested manually.
+
+        * platform/mediastream/CaptureDevice.h: Add concept of default device.
+        (WebCore::CaptureDevice::isDefault const):
+        (WebCore::CaptureDevice::setIsDefault):
+        (WebCore::CaptureDevice::encode const):
+        (WebCore::CaptureDevice::decode):
+
+        * platform/mediastream/ios/AVAudioSessionCaptureDevice.h: Don't retain port
+        description, it is never used.
+        * platform/mediastream/ios/AVAudioSessionCaptureDevice.mm:
+        (WebCore::AVAudioSessionCaptureDevice::create): Add default input parameter.
+        (WebCore::AVAudioSessionCaptureDevice::AVAudioSessionCaptureDevice): Set enabled
+        and default attributes.
+
+        * platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.h:
+        * platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm:
+        (-[WebAVAudioSessionAvailableInputsListener initWithCallback:audioSession:]): Take
+        parent object and audio session. Listen for session route change notification.
+        (-[WebAVAudioSessionAvailableInputsListener invalidate]):
+        (-[WebAVAudioSessionAvailableInputsListener routeDidChange:]):
+        (WebCore::AVAudioSessionCaptureDeviceManager::AVAudioSessionCaptureDeviceManager):
+        Allocate and use an auxiliary audio session because it isn't possible to enumerate
+        all audio inputs without one.
+        (WebCore::AVAudioSessionCaptureDeviceManager::audioSessionDeviceWithUID): No need
+        to call refreshAudioCaptureDevices, audioSessionCaptureDevices does it if necessary.
+        (WebCore::AVAudioSessionCaptureDeviceManager::scheduleUpdateCaptureDevices): New,
+        refresh devices on a task queue because we frequently get more than one notification
+        when a route changes.
+        (WebCore::AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices): Sort devices
+        so the default is always first. Only call deviceChanged when something actually changes.
+        (-[WebAVAudioSessionAvailableInputsListener initWithCallback:]): Deleted.
+        (-[WebAVAudioSessionAvailableInputsListener observeValueForKeyPath:ofObject:change:context:]): Deleted.
+
+        * platform/mediastream/mac/CoreAudioCaptureDevice.cpp:
+        (WebCore::getDeviceInfo): Deal with input and output devices. Translate the data
+        source name if possible.
+        (WebCore::CoreAudioCaptureDevice::create):
+        (WebCore::CoreAudioCaptureDevice::CoreAudioCaptureDevice): Set new `default` attribute.
+        (WebCore::CoreAudioCaptureDevice::defaultDevice): New.
+        * platform/mediastream/mac/CoreAudioCaptureDevice.h:
+
+        * platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp:
+        (WebCore::CoreAudioCaptureDeviceManager::scheduleUpdateCaptureDevices): New, coalesce
+        calls to refreshAudioCaptureDevices.
+        (WebCore::CoreAudioCaptureDeviceManager::coreAudioCaptureDevices): 
+        (WebCore::computeAudioDeviceList): No need to check for the default device explicitly.
+        (WebCore::CoreAudioCaptureDeviceManager::refreshAudioCaptureDevices):
+        (WebCore::getDefaultCaptureInputDevice): Deleted.
+        (WebCore::getDefaultCaptureOutputDevice): Deleted.
+        * platform/mediastream/mac/CoreAudioCaptureDeviceManager.h:
+
</ins><span class="cx"> 2020-11-11  Noam Rosenthal  <noam@webkit.org>
</span><span class="cx"> 
</span><span class="cx">         ContentfulPaintChecker should not trigger plugin snapshotting
</span></span></pre></div>
<a id="trunkSourceWebCorePALChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/PAL/ChangeLog (269687 => 269688)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/PAL/ChangeLog       2020-11-11 17:23:11 UTC (rev 269687)
+++ trunk/Source/WebCore/PAL/ChangeLog  2020-11-11 18:06:46 UTC (rev 269688)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2020-11-11  Eric Carlson  <eric.carlson@apple.com>
+
+        USB microphone not recognized iOS Safari
+        https://bugs.webkit.org/show_bug.cgi?id=211192
+        <rdar://problem/62607313>
+
+        Reviewed by Youenn Fablet.
+
+        * pal/spi/cocoa/AVFoundationSPI.h: Declare +[AVAudioSession initAuxiliarySession].
+
</ins><span class="cx"> 2020-11-10  Jer Noble  <jer.noble@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Unreviewed internal macOS build-fix.
</span></span></pre></div>
<a id="trunkSourceWebCorePALpalspicocoaAVFoundationSPIh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/PAL/pal/spi/cocoa/AVFoundationSPI.h (269687 => 269688)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/PAL/pal/spi/cocoa/AVFoundationSPI.h 2020-11-11 17:23:11 UTC (rev 269687)
+++ trunk/Source/WebCore/PAL/pal/spi/cocoa/AVFoundationSPI.h    2020-11-11 18:06:46 UTC (rev 269688)
</span><span class="lines">@@ -355,12 +355,13 @@
</span><span class="cx"> @end
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-#if !USE(APPLE_INTERNAL_SDK) && PLATFORM(IOS_FAMILY) && !PLATFORM(IOS_FAMILY_SIMULATOR) && !PLATFORM(MACCATALYST)
</del><ins>+#if !USE(APPLE_INTERNAL_SDK) && PLATFORM(IOS_FAMILY) && !PLATFORM(MACCATALYST)
</ins><span class="cx"> #import <AVFoundation/AVAudioSession.h>
</span><span class="cx"> 
</span><span class="cx"> NS_ASSUME_NONNULL_BEGIN
</span><span class="cx"> 
</span><span class="cx"> @interface AVAudioSession (AVAudioSessionPrivate)
</span><ins>+- (instancetype)initAuxiliarySession;
</ins><span class="cx"> @property (readonly) NSString* routingContextUID;
</span><span class="cx"> @end
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamCaptureDeviceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/CaptureDevice.h (269687 => 269688)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/CaptureDevice.h        2020-11-11 17:23:11 UTC (rev 269687)
+++ trunk/Source/WebCore/platform/mediastream/CaptureDevice.h   2020-11-11 18:06:46 UTC (rev 269688)
</span><span class="lines">@@ -63,6 +63,9 @@
</span><span class="cx">     bool enabled() const { return m_enabled; }
</span><span class="cx">     void setEnabled(bool enabled) { m_enabled = enabled; }
</span><span class="cx"> 
</span><ins>+    bool isDefault() const { return m_default; }
+    void setIsDefault(bool isDefault) { m_default = isDefault; }
+
</ins><span class="cx">     explicit operator bool() const { return m_type != DeviceType::Unknown; }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MEDIA_STREAM)
</span><span class="lines">@@ -73,6 +76,7 @@
</span><span class="cx">         encoder << m_label;
</span><span class="cx">         encoder << m_groupId;
</span><span class="cx">         encoder << m_enabled;
</span><ins>+        encoder << m_default;
</ins><span class="cx">         encoder << m_type;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -99,6 +103,11 @@
</span><span class="cx">         if (!enabled)
</span><span class="cx">             return WTF::nullopt;
</span><span class="cx"> 
</span><ins>+        Optional<bool> isDefault;
+        decoder >> isDefault;
+        if (!isDefault)
+            return WTF::nullopt;
+
</ins><span class="cx">         Optional<CaptureDevice::DeviceType> type;
</span><span class="cx">         decoder >> type;
</span><span class="cx">         if (!type)
</span><span class="lines">@@ -106,6 +115,7 @@
</span><span class="cx"> 
</span><span class="cx">         Optional<CaptureDevice> device = {{ WTFMove(*persistentId), WTFMove(*type), WTFMove(*label), WTFMove(*groupId) }};
</span><span class="cx">         device->setEnabled(*enabled);
</span><ins>+        device->setIsDefault(*isDefault);
</ins><span class="cx">         return device;
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="lines">@@ -116,6 +126,7 @@
</span><span class="cx">     String m_label;
</span><span class="cx">     String m_groupId;
</span><span class="cx">     bool m_enabled { false };
</span><ins>+    bool m_default { false };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamiosAVAudioSessionCaptureDeviceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDevice.h (269687 => 269688)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDevice.h      2020-11-11 17:23:11 UTC (rev 269687)
+++ trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDevice.h 2020-11-11 18:06:46 UTC (rev 269688)
</span><span class="lines">@@ -36,13 +36,11 @@
</span><span class="cx"> 
</span><span class="cx"> class AVAudioSessionCaptureDevice : public CaptureDevice {
</span><span class="cx"> public:
</span><del>-    static AVAudioSessionCaptureDevice create(AVAudioSessionPortDescription*);
</del><ins>+    static AVAudioSessionCaptureDevice create(AVAudioSessionPortDescription *deviceInput, AVAudioSessionPortDescription *defaultInput);
</ins><span class="cx">     virtual ~AVAudioSessionCaptureDevice() = default;
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    AVAudioSessionCaptureDevice(AVAudioSessionPortDescription*, const String& persistentID, const String& label);
-
-    RetainPtr<AVAudioSessionPortDescription> m_portDescription;
</del><ins>+    AVAudioSessionCaptureDevice(AVAudioSessionPortDescription *deviceInput, AVAudioSessionPortDescription *defaultInput);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamiosAVAudioSessionCaptureDevicemm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDevice.mm (269687 => 269688)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDevice.mm     2020-11-11 17:23:11 UTC (rev 269687)
+++ trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDevice.mm        2020-11-11 18:06:46 UTC (rev 269688)
</span><span class="lines">@@ -32,19 +32,16 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-AVAudioSessionCaptureDevice AVAudioSessionCaptureDevice::create(AVAudioSessionPortDescription* portDescription)
</del><ins>+AVAudioSessionCaptureDevice AVAudioSessionCaptureDevice::create(AVAudioSessionPortDescription* deviceInput, AVAudioSessionPortDescription *defaultInput)
</ins><span class="cx"> {
</span><del>-    String persistentID = portDescription.UID;
-    String label = portDescription.portName;
-    auto device = AVAudioSessionCaptureDevice(portDescription, persistentID, label);
-    device.setEnabled(portDescription.dataSources.count);
-    return device;
</del><ins>+    return AVAudioSessionCaptureDevice(deviceInput, defaultInput);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-AVAudioSessionCaptureDevice::AVAudioSessionCaptureDevice(AVAudioSessionPortDescription* portDescription, const String& persistentID, const String& label)
-    : CaptureDevice(persistentID, CaptureDevice::DeviceType::Microphone, label)
-    , m_portDescription(portDescription)
</del><ins>+AVAudioSessionCaptureDevice::AVAudioSessionCaptureDevice(AVAudioSessionPortDescription *deviceInput, AVAudioSessionPortDescription *defaultInput)
+    : CaptureDevice(deviceInput.UID, CaptureDevice::DeviceType::Microphone, deviceInput.portName)
</ins><span class="cx"> {
</span><ins>+    setEnabled(true);
+    setIsDefault(defaultInput && [defaultInput.UID isEqualToString:deviceInput.UID]);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamiosAVAudioSessionCaptureDeviceManagerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.h (269687 => 269688)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.h       2020-11-11 17:23:11 UTC (rev 269687)
+++ trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.h  2020-11-11 18:06:46 UTC (rev 269688)
</span><span class="lines">@@ -28,10 +28,12 @@
</span><span class="cx"> #if ENABLE(MEDIA_STREAM) && PLATFORM(IOS_FAMILY)
</span><span class="cx"> 
</span><span class="cx"> #include "CaptureDeviceManager.h"
</span><ins>+#include "GenericTaskQueue.h"
</ins><span class="cx"> #include <wtf/Forward.h>
</span><span class="cx"> #include <wtf/HashSet.h>
</span><span class="cx"> #include <wtf/RetainPtr.h>
</span><span class="cx"> 
</span><ins>+OBJC_CLASS AVAudioSession;
</ins><span class="cx"> OBJC_CLASS WebAVAudioSessionAvailableInputsListener;
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="lines">@@ -48,19 +50,23 @@
</span><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><del>-    Vector<AVAudioSessionCaptureDevice>& audioSessionCaptureDevices();
</del><span class="cx">     Optional<AVAudioSessionCaptureDevice> audioSessionDeviceWithUID(const String&);
</span><ins>+    
+    void scheduleUpdateCaptureDevices();
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    AVAudioSessionCaptureDeviceManager() = default;
</del><ins>+    AVAudioSessionCaptureDeviceManager();
</ins><span class="cx">     ~AVAudioSessionCaptureDeviceManager();
</span><span class="cx"> 
</span><span class="cx">     void refreshAudioCaptureDevices();
</span><ins>+    Vector<AVAudioSessionCaptureDevice>& audioSessionCaptureDevices();
</ins><span class="cx"> 
</span><span class="cx">     Optional<Vector<CaptureDevice>> m_devices;
</span><span class="cx">     Vector<CaptureDevice> m_speakerDevices;
</span><span class="cx">     Optional<Vector<AVAudioSessionCaptureDevice>> m_audioSessionCaptureDevices;
</span><span class="cx">     RetainPtr<WebAVAudioSessionAvailableInputsListener> m_listener;
</span><ins>+    RetainPtr<AVAudioSession> m_audioSession;
+    GenericTaskQueue<Timer> m_updateDeviceStateQueue;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamiosAVAudioSessionCaptureDeviceManagermm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm (269687 => 269688)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm      2020-11-11 17:23:11 UTC (rev 269687)
+++ trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm 2020-11-11 18:06:46 UTC (rev 269688)
</span><span class="lines">@@ -29,27 +29,32 @@
</span><span class="cx"> #if ENABLE(MEDIA_STREAM) && PLATFORM(IOS_FAMILY)
</span><span class="cx"> 
</span><span class="cx"> #import "AVAudioSessionCaptureDevice.h"
</span><ins>+#import "Logging.h"
</ins><span class="cx"> #import "RealtimeMediaSourceCenter.h"
</span><span class="cx"> #import <AVFoundation/AVAudioSession.h>
</span><ins>+#import <pal/spi/cocoa/AVFoundationSPI.h>
+#import <wtf/Assertions.h>
+#import <wtf/MainThread.h>
</ins><span class="cx"> #import <wtf/Vector.h>
</span><span class="cx"> 
</span><span class="cx"> #import <pal/cocoa/AVFoundationSoftLink.h>
</span><span class="cx"> 
</span><del>-void* AvailableInputsContext = &AvailableInputsContext;
-
</del><span class="cx"> @interface WebAVAudioSessionAvailableInputsListener : NSObject {
</span><del>-    WTF::Function<void()> _callback;
</del><ins>+    WebCore::AVAudioSessionCaptureDeviceManager* _callback;
</ins><span class="cx"> }
</span><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> @implementation WebAVAudioSessionAvailableInputsListener
</span><del>-- (id)initWithCallback:(WTF::Function<void()>&&)callback
</del><ins>+- (id)initWithCallback:(WebCore::AVAudioSessionCaptureDeviceManager *)callback audioSession:(AVAudioSession *)session
</ins><span class="cx"> {
</span><span class="cx">     self = [super init];
</span><span class="cx">     if (!self)
</span><span class="cx">         return nil;
</span><span class="cx"> 
</span><del>-    _callback = WTFMove(callback);
</del><ins>+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(routeDidChange:) name:PAL::get_AVFoundation_AVAudioSessionRouteChangeNotification() object:session];
+
+    _callback = callback;
+
</ins><span class="cx">     return self;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -56,16 +61,21 @@
</span><span class="cx"> - (void)invalidate
</span><span class="cx"> {
</span><span class="cx">     _callback = nullptr;
</span><ins>+    [[NSNotificationCenter defaultCenter] removeObserver:self];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context
</del><ins>+- (void)routeDidChange:(NSNotification *)notification
</ins><span class="cx"> {
</span><del>-    UNUSED_PARAM(keyPath);
-    UNUSED_PARAM(object);
-    UNUSED_PARAM(change);
-    if (context == AvailableInputsContext && _callback)
-        _callback();
</del><ins>+    if (!_callback)
+        return;
+
+    callOnWebThreadOrDispatchAsyncOnMainThread([protectedSelf = retainPtr(self)]() mutable {
+        if (auto* callback = protectedSelf->_callback)
+            callback->scheduleUpdateCaptureDevices();
+    });
+
</ins><span class="cx"> }
</span><ins>+
</ins><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="lines">@@ -76,6 +86,24 @@
</span><span class="cx">     return manager;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+AVAudioSessionCaptureDeviceManager::AVAudioSessionCaptureDeviceManager()
+{
+#if !PLATFORM(MACCATALYST)
+    m_audioSession = adoptNS([[PAL::getAVAudioSessionClass() alloc] initAuxiliarySession]);
+#else
+    // FIXME: Figure out if this is correct for Catalyst, where auxiliary session isn't available.
+    m_audioSession = [PAL::getAVAudioSessionClass() sharedInstance];
+#endif
+    
+    NSError *error = nil;
+    auto options = AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionMixWithOthers;
+    [m_audioSession setCategory:AVAudioSessionCategoryPlayAndRecord mode:AVAudioSessionModeVideoChat options:options error:&error];
+    if (error) {
+        RELEASE_LOG_ERROR(WebRTC, "Failed to set audio session category with error: %@.", error.localizedDescription);
+        return;
+    }
+}
+
</ins><span class="cx"> AVAudioSessionCaptureDeviceManager::~AVAudioSessionCaptureDeviceManager()
</span><span class="cx"> {
</span><span class="cx">     [m_listener invalidate];
</span><span class="lines">@@ -108,9 +136,6 @@
</span><span class="cx"> 
</span><span class="cx"> Optional<AVAudioSessionCaptureDevice> AVAudioSessionCaptureDeviceManager::audioSessionDeviceWithUID(const String& deviceID)
</span><span class="cx"> {
</span><del>-    if (!m_audioSessionCaptureDevices)
-        refreshAudioCaptureDevices();
-
</del><span class="cx">     for (auto& device : audioSessionCaptureDevices()) {
</span><span class="cx">         if (device.persistentId() == deviceID)
</span><span class="cx">             return device;
</span><span class="lines">@@ -118,30 +143,59 @@
</span><span class="cx">     return WTF::nullopt;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void AVAudioSessionCaptureDeviceManager::scheduleUpdateCaptureDevices()
+{
+    if (m_updateDeviceStateQueue.hasPendingTasks())
+        return;
+
+    m_updateDeviceStateQueue.enqueueTask([this] {
+        refreshAudioCaptureDevices();
+    });
+}
+
</ins><span class="cx"> void AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices()
</span><span class="cx"> {
</span><del>-    if (!m_listener) {
-        m_listener = adoptNS([[WebAVAudioSessionAvailableInputsListener alloc] initWithCallback:[this] {
-            refreshAudioCaptureDevices();
-        }]);
-        [[PAL::getAVAudioSessionClass() sharedInstance] addObserver:m_listener.get() forKeyPath:@"availableInputs" options:0 context:AvailableInputsContext];
-    }
</del><ins>+    if (!m_listener)
+        m_listener = adoptNS([[WebAVAudioSessionAvailableInputsListener alloc] initWithCallback:this audioSession:m_audioSession.get()]);
</ins><span class="cx"> 
</span><ins>+    NSError *error = nil;
+    [m_audioSession setActive:YES withOptions:0 error:&error];
+    if (error)
+        RELEASE_LOG_ERROR(WebRTC, "Failed to activate audio session with error: %@.", error.localizedDescription);
+
</ins><span class="cx">     Vector<AVAudioSessionCaptureDevice> newAudioDevices;
</span><span class="cx">     Vector<CaptureDevice> newDevices;
</span><del>-
-    for (AVAudioSessionPortDescription *portDescription in [PAL::getAVAudioSessionClass() sharedInstance].availableInputs) {
-        auto audioDevice = AVAudioSessionCaptureDevice::create(portDescription);
</del><ins>+    auto *defaultInput = [m_audioSession currentRoute].inputs.firstObject;
+    for (AVAudioSessionPortDescription *portDescription in [m_audioSession availableInputs]) {
+        auto audioDevice = AVAudioSessionCaptureDevice::create(portDescription, defaultInput);
</ins><span class="cx">         newDevices.append(audioDevice);
</span><span class="cx">         newAudioDevices.append(WTFMove(audioDevice));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool firstTime = !m_devices;
+    bool haveDeviceChanges = !m_devices || newAudioDevices.size() != m_devices->size();
+    if (!haveDeviceChanges) {
+        for (size_t i = 0; i < newAudioDevices.size(); ++i) {
+            auto& oldState = (*m_devices)[i];
+            auto& newState = newAudioDevices[i];
+            if (newState.type() != oldState.type() || newState.persistentId() != oldState.persistentId() || newState.enabled() != oldState.enabled() || newState.isDefault() != oldState.isDefault())
+                haveDeviceChanges = true;
+        }
+    }
+
+    if (!haveDeviceChanges && !firstTime)
+        return;
+
</ins><span class="cx">     m_audioSessionCaptureDevices = WTFMove(newAudioDevices);
</span><ins>+    std::sort(newDevices.begin(), newDevices.end(), [] (auto& first, auto& second) -> bool {
+        return first.isDefault() && !second.isDefault();
+    });
</ins><span class="cx">     m_devices = WTFMove(newDevices);
</span><span class="cx"> 
</span><del>-    deviceChanged();
</del><ins>+    if (!firstTime)
+        deviceChanged();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><del>-#endif // ENABLE(MEDIA_STREAM) && PLATFORM(MAC)
</del><ins>+#endif // ENABLE(MEDIA_STREAM) && PLATFORM(IOS_FAMILY)
</ins></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacCoreAudioCaptureDevicecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDevice.cpp (269687 => 269688)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDevice.cpp 2020-11-11 17:23:11 UTC (rev 269687)
+++ trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDevice.cpp    2020-11-11 18:06:46 UTC (rev 269688)
</span><span class="lines">@@ -38,7 +38,7 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> using namespace PAL;
</span><span class="cx"> 
</span><del>-static bool getDeviceInfo(uint32_t deviceID, String& persistentID, String& label)
</del><ins>+static bool getDeviceInfo(uint32_t deviceID, CaptureDevice::DeviceType type, String& persistentID, String& label)
</ins><span class="cx"> {
</span><span class="cx">     CFStringRef uniqueID;
</span><span class="cx">     AudioObjectPropertyAddress address { kAudioDevicePropertyDeviceUID, kAudioDevicePropertyScopeInput, kAudioObjectPropertyElementMaster };
</span><span class="lines">@@ -51,14 +51,30 @@
</span><span class="cx">     persistentID = uniqueID;
</span><span class="cx">     CFRelease(uniqueID);
</span><span class="cx"> 
</span><del>-    CFStringRef localizedName;
-    address = { kAudioObjectPropertyName, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
-    dataSize = sizeof(localizedName);
-    err = AudioObjectGetPropertyData(static_cast<UInt32>(deviceID), &address, 0, nullptr, &dataSize, &localizedName);
</del><ins>+    CFStringRef localizedName = nullptr;
+    AudioObjectPropertyScope scope = type == CaptureDevice::DeviceType::Microphone ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
+    address = { kAudioDevicePropertyDataSource, scope, kAudioObjectPropertyElementMaster };
+    uint32_t sourceID;
+    dataSize = sizeof(sourceID);
+    err = AudioObjectGetPropertyData(static_cast<UInt32>(deviceID), &address, 0, nullptr, &dataSize, &sourceID);
+    if (!err) {
+        AudioValueTranslation translation = { &deviceID, sizeof(deviceID), &localizedName, sizeof(localizedName) };
+        address = { kAudioDevicePropertyDataSourceNameForIDCFString, scope, kAudioObjectPropertyElementMaster };
+        dataSize = sizeof(translation);
+        err = AudioObjectGetPropertyData(static_cast<UInt32>(deviceID), &address, 0, nullptr, &dataSize, &translation);
+    }
+
+    if (err || !localizedName || !CFStringGetLength(localizedName)) {
+        address = { kAudioObjectPropertyName, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+        dataSize = sizeof(localizedName);
+        err = AudioObjectGetPropertyData(static_cast<UInt32>(deviceID), &address, 0, nullptr, &dataSize, &localizedName);
+    }
+
</ins><span class="cx">     if (err) {
</span><span class="cx">         RELEASE_LOG_ERROR(WebRTC, "CoreAudioCaptureDevice::getDeviceInfo failed to get device name with error %d (%.4s)", (int)err, (char*)&err);
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><ins>+
</ins><span class="cx">     label = localizedName;
</span><span class="cx">     CFRelease(localizedName);
</span><span class="cx"> 
</span><span class="lines">@@ -70,7 +86,7 @@
</span><span class="cx">     ASSERT(type == CaptureDevice::DeviceType::Microphone || type == CaptureDevice::DeviceType::Speaker);
</span><span class="cx">     String persistentID;
</span><span class="cx">     String label;
</span><del>-    if (!getDeviceInfo(deviceID, persistentID, label))
</del><ins>+    if (!getDeviceInfo(deviceID, type, persistentID, label))
</ins><span class="cx">         return WTF::nullopt;
</span><span class="cx"> 
</span><span class="cx">     return CoreAudioCaptureDevice(deviceID, persistentID, type, label, groupID.isNull() ? persistentID : groupID);
</span><span class="lines">@@ -80,7 +96,22 @@
</span><span class="cx">     : CaptureDevice(persistentID, deviceType, label, groupID)
</span><span class="cx">     , m_deviceID(deviceID)
</span><span class="cx"> {
</span><del>-    setEnabled(isAlive());
</del><ins>+    AudioObjectPropertyAddress address { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+    UInt32 state = 0;
+    UInt32 dataSize = sizeof(state);
+    auto err = AudioObjectGetPropertyData(static_cast<UInt32>(m_deviceID), &address, 0, nullptr, &dataSize, &state);
+    if (err)
+        RELEASE_LOG_ERROR(WebRTC, "CoreAudioCaptureDevice::CoreAudioCaptureDevice(%p) failed to get \"is alive\" with error %d (%.4s)", this, (int)err, (char*)&err);
+    setEnabled(!err && state);
+
+    UInt32 property = deviceType == CaptureDevice::DeviceType::Microphone ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice;
+    address = { property, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+    AudioDeviceID defaultID = kAudioDeviceUnknown;
+    dataSize = sizeof(defaultID);
+    err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &address, 0, nullptr, &dataSize, &defaultID);
+    if (err)
+        RELEASE_LOG_ERROR(WebRTC, "CoreAudioCaptureDevice::CoreAudioCaptureDevice(%p) failed to get \"is default\" with error %d (%.4s)", this, (int)err, (char*)&err);
+    setIsDefault(!err && defaultID == m_deviceID);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Vector<AudioDeviceID> CoreAudioCaptureDevice::relatedAudioDeviceIDs(AudioDeviceID deviceID)
</span><span class="lines">@@ -115,16 +146,6 @@
</span><span class="cx">     return m_deviceClock;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool CoreAudioCaptureDevice::isAlive()
-{
-    AudioObjectPropertyAddress address = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
-    UInt32 state = 0;
-    UInt32 dataSize = sizeof(state);
-    if (AudioObjectGetPropertyData(static_cast<UInt32>(m_deviceID), &address, 0, nullptr, &dataSize, &state))
-        return false;
-    return state;
-}
-
</del><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(MEDIA_STREAM) && PLATFORM(MAC)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacCoreAudioCaptureDeviceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDevice.h (269687 => 269688)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDevice.h   2020-11-11 17:23:11 UTC (rev 269687)
+++ trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDevice.h      2020-11-11 18:06:46 UTC (rev 269688)
</span><span class="lines">@@ -48,7 +48,6 @@
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     CoreAudioCaptureDevice(uint32_t, const String& persistentID, DeviceType, const String& label, const String& groupID);
</span><del>-    bool isAlive();
</del><span class="cx"> 
</span><span class="cx">     uint32_t m_deviceID { 0 };
</span><span class="cx">     RetainPtr<CMClockRef> m_deviceClock;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacCoreAudioCaptureDeviceManagercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp (269687 => 269688)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp  2020-11-11 17:23:11 UTC (rev 269687)
+++ trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp     2020-11-11 18:06:46 UTC (rev 269688)
</span><span class="lines">@@ -128,30 +128,16 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static inline Optional<CoreAudioCaptureDevice> getDefaultCaptureInputDevice()
</del><ins>+void CoreAudioCaptureDeviceManager::scheduleUpdateCaptureDevices()
</ins><span class="cx"> {
</span><del>-    AudioObjectPropertyAddress address { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
-    UInt32 propertySize = sizeof(AudioDeviceID);
-    AudioDeviceID deviceID = kAudioDeviceUnknown;
-    auto err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &address, 0, nullptr, &propertySize, &deviceID);
</del><ins>+    if (m_updateDeviceStateQueue.hasPendingTasks())
+        return;
</ins><span class="cx"> 
</span><del>-    if (err != noErr || deviceID == kAudioDeviceUnknown)
-        return { };
-    return CoreAudioCaptureDevice::create(deviceID, CaptureDevice::DeviceType::Microphone, { });
</del><ins>+    m_updateDeviceStateQueue.enqueueTask([this] {
+        refreshAudioCaptureDevices(NotifyIfDevicesHaveChanged::Notify);
+    });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static inline Optional<CoreAudioCaptureDevice> getDefaultCaptureOutputDevice()
-{
-    AudioObjectPropertyAddress address { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
-    UInt32 propertySize = sizeof(AudioDeviceID);
-    AudioDeviceID deviceID = kAudioDeviceUnknown;
-    auto err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &address, 0, nullptr, &propertySize, &deviceID);
-
-    if (err != noErr || deviceID == kAudioDeviceUnknown)
-        return { };
-    return CoreAudioCaptureDevice::create(deviceID, CaptureDevice::DeviceType::Speaker, { });
-}
-
</del><span class="cx"> Vector<CoreAudioCaptureDevice>& CoreAudioCaptureDeviceManager::coreAudioCaptureDevices()
</span><span class="cx"> {
</span><span class="cx">     static bool initialized;
</span><span class="lines">@@ -165,7 +151,7 @@
</span><span class="cx">                 notify |= (properties[i].mSelector == kAudioHardwarePropertyDevices || properties[i].mSelector == kAudioHardwarePropertyDefaultInputDevice || properties[i].mSelector == kAudioHardwarePropertyDefaultOutputDevice);
</span><span class="cx"> 
</span><span class="cx">             if (notify)
</span><del>-                CoreAudioCaptureDeviceManager::singleton().refreshAudioCaptureDevices(NotifyIfDevicesHaveChanged::Notify);
</del><ins>+                CoreAudioCaptureDeviceManager::singleton().scheduleUpdateCaptureDevices();
</ins><span class="cx">         };
</span><span class="cx"> 
</span><span class="cx">         AudioObjectPropertyAddress address = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
</span><span class="lines">@@ -223,10 +209,6 @@
</span><span class="cx"> 
</span><span class="cx">     Vector<CoreAudioCaptureDevice> audioDevices;
</span><span class="cx"> 
</span><del>-    auto defaultInputDevice = getDefaultCaptureInputDevice();
-    if (defaultInputDevice)
-        audioDevices.append(WTFMove(*defaultInputDevice));
-
</del><span class="cx">     // Microphones
</span><span class="cx">     for (size_t i = 0; i < deviceCount; i++) {
</span><span class="cx">         AudioObjectID deviceID = deviceIDs[i];
</span><span class="lines">@@ -239,10 +221,6 @@
</span><span class="cx">             audioDevices.append(WTFMove(microphoneDevice.value()));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    auto defaultOutputDevice = getDefaultCaptureOutputDevice();
-    if (defaultOutputDevice)
-        audioDevices.append(WTFMove(*defaultOutputDevice));
-
</del><span class="cx">     // Speakers
</span><span class="cx">     for (size_t i = 0; i < deviceCount; i++) {
</span><span class="cx">         AudioObjectID deviceID = deviceIDs[i];
</span><span class="lines">@@ -285,26 +263,27 @@
</span><span class="cx">     bool haveDeviceChanges = audioDevices.size() != m_coreAudioCaptureDevices.size();
</span><span class="cx">     if (!haveDeviceChanges) {
</span><span class="cx">         for (size_t cptr = 0; cptr < audioDevices.size(); ++cptr) {
</span><del>-            if (audioDevices[cptr].type() != m_coreAudioCaptureDevices[cptr].type() || audioDevices[cptr].deviceID() != m_coreAudioCaptureDevices[cptr].deviceID() || audioDevices[cptr].enabled() != m_coreAudioCaptureDevices[cptr].enabled()) {
</del><ins>+            auto& oldDevice = m_coreAudioCaptureDevices[cptr];
+            auto& newDevice = audioDevices[cptr];
+            if (newDevice.type() != oldDevice.type() || newDevice.deviceID() != oldDevice.deviceID() || newDevice.isDefault() != oldDevice.isDefault() || newDevice.enabled() != oldDevice.enabled() || newDevice.isDefault() != oldDevice.isDefault())
</ins><span class="cx">                 haveDeviceChanges = true;
</span><del>-                break;
-            }
</del><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     if (!haveDeviceChanges)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><ins>+    std::sort(audioDevices.begin(), audioDevices.end(), [] (auto& first, auto& second) -> bool {
+        return first.isDefault() && !second.isDefault();
+    });
</ins><span class="cx">     m_coreAudioCaptureDevices = WTFMove(audioDevices);
</span><span class="cx"> 
</span><span class="cx">     m_captureDevices.clear();
</span><span class="cx">     m_speakerDevices.clear();
</span><span class="cx">     for (auto& device : m_coreAudioCaptureDevices) {
</span><del>-        CaptureDevice captureDevice { device.persistentId(), device.type(), device.label(), device.groupId() };
-        captureDevice.setEnabled(device.enabled());
</del><span class="cx">         if (device.type() == CaptureDevice::DeviceType::Microphone)
</span><del>-            m_captureDevices.append(WTFMove(captureDevice));
</del><ins>+            m_captureDevices.append(device);
</ins><span class="cx">         else
</span><del>-            m_speakerDevices.append(WTFMove(captureDevice));
</del><ins>+            m_speakerDevices.append(device);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (notify == NotifyIfDevicesHaveChanged::Notify) {
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacCoreAudioCaptureDeviceManagerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDeviceManager.h (269687 => 269688)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDeviceManager.h    2020-11-11 17:23:11 UTC (rev 269687)
+++ trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDeviceManager.h       2020-11-11 18:06:46 UTC (rev 269688)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include "CaptureDevice.h"
</span><span class="cx"> #include "CaptureDeviceManager.h"
</span><ins>+#include "GenericTaskQueue.h"
</ins><span class="cx"> #include <CoreAudio/CoreAudio.h>
</span><span class="cx"> #include <wtf/HashMap.h>
</span><span class="cx"> #include <wtf/RefPtr.h>
</span><span class="lines">@@ -57,10 +58,12 @@
</span><span class="cx"> 
</span><span class="cx">     enum class NotifyIfDevicesHaveChanged { Notify, DoNotNotify };
</span><span class="cx">     void refreshAudioCaptureDevices(NotifyIfDevicesHaveChanged);
</span><ins>+    void scheduleUpdateCaptureDevices();
</ins><span class="cx"> 
</span><span class="cx">     Vector<CaptureDevice> m_captureDevices;
</span><span class="cx">     Vector<CaptureDevice> m_speakerDevices;
</span><span class="cx">     Vector<CoreAudioCaptureDevice> m_coreAudioCaptureDevices;
</span><ins>+    GenericTaskQueue<Timer> m_updateDeviceStateQueue;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre>
</div>
</div>

</body>
</html>