⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 271471 in webkit


Ignore:
Timestamp:
Jan 13, 2021, 4:01:37 PM (6 years ago)
Author:
jer.noble@apple.com
Message:

Source/WebCore:
[HANG] 496ms to 1360ms in WebCore::AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices()
https://bugs.webkit.org/show_bug.cgi?id=220471

Reviewed by Youenn Fablet.

Refactor RealtimeMediaSourceCenter::getMediaStreamDevices() to take a completion handler, rather than
synchronously return a Vector of CaptureDevices. This also requires all CaptureDeviceManager subclasses
to support taking a completion handler themselves. By default, all CaptureDeviceManagers will support
the CompletionHandler path by just synchronously calling the completion handler with the existing
synchronous method. But for AVAudioSessionCaptureDeviceManager, override that default implementation by
activating the AVAudioSession on a background thread, and querying that session's inputs on a background
thread as well.

  • platform/mediastream/CaptureDeviceManager.h:
  • platform/mediastream/RealtimeMediaSourceCenter.cpp:

(WebCore::RealtimeMediaSourceCenter::getMediaStreamDevices):

  • platform/mediastream/RealtimeMediaSourceCenter.h:
  • platform/mediastream/RealtimeMediaSourceFactory.h:

(WebCore::AudioCaptureFactory::getSpeakerDevices const):

  • platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.h:
  • platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm:

(WebCore::AVAudioSessionCaptureDeviceManager::audioSessionDeviceWithUID):
(WebCore::AVAudioSessionCaptureDeviceManager::scheduleUpdateCaptureDevices):
(WebCore::AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices):
(WebCore::AVAudioSessionCaptureDeviceManager::getCaptureDevices):
(WebCore::AVAudioSessionCaptureDeviceManager::activateAudioSession):
(WebCore::AVAudioSessionCaptureDeviceManager::retrieveAudioSessionCaptureDevices const):
(WebCore::AVAudioSessionCaptureDeviceManager::setAudioCaptureDevices):
(WebCore::AVAudioSessionCaptureDeviceManager::audioSessionCaptureDevices): Deleted.

Source/WebKit:
[HANG] 496ms to 1360ms in WebCore::AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices()
https://bugs.webkit.org/show_bug.cgi?id=220471

Reviewed by Youenn Fablet.

Use the completion-handler version of RealtimeMediaSourceCenter::getMediaStreamDevices().

  • UIProcess/UserMediaPermissionRequestManagerProxy.cpp:

(WebKit::UserMediaPermissionRequestManagerProxy::computeFilteredDeviceList):
(WebKit::UserMediaPermissionRequestManagerProxy::enumerateMediaDevicesForFrame):

  • UIProcess/UserMediaPermissionRequestManagerProxy.h:
  • UIProcess/UserMediaProcessManager.cpp:

(WebKit::UserMediaProcessManager::updateCaptureDevices):
(WebKit::UserMediaProcessManager::beginMonitoringCaptureDevices):

  • UIProcess/UserMediaProcessManager.h:

LayoutTests:
[Cocoa] Support key rotation with HLS-backed encrypted media streams
https://bugs.webkit.org/show_bug.cgi?id=220493
<rdar://68227709>

Reviewed by Youenn Fablet.

Fix a broken layout test; the test enumerates devices, then uses the deviceIds returned to generate
constraints for a call to getUserMedia(). However, it assumes all devices will either be of kind
'audioinput' or 'videoinput'. If an 'audiooutput' device is returned (as the MockRealtimeMediaSourceCenter
does), then the test turns that into a video capture constraint, which fails.

  • fast/mediastream/get-user-media-device-id.html:
Location:
trunk
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r271461 r271471  
     12021-01-13  Jer Noble  <jer.noble@apple.com>
     2
     3        [Cocoa] Support key rotation with HLS-backed encrypted media streams
     4        https://bugs.webkit.org/show_bug.cgi?id=220493
     5        <rdar://68227709>
     6
     7        Reviewed by Youenn Fablet.
     8
     9        Fix a broken layout test; the test enumerates devices, then uses the deviceIds returned to generate
     10        constraints for a call to getUserMedia(). However, it assumes all devices will either be of kind
     11        'audioinput' or 'videoinput'. If an 'audiooutput' device is returned (as the MockRealtimeMediaSourceCenter
     12        does), then the test turns that into a video capture constraint, which fails.
     13
     14        * fast/mediastream/get-user-media-device-id.html:
     15
    1162021-01-13  Ryan Haddad  <ryanhaddad@apple.com>
    217
  • trunk/LayoutTests/fast/mediastream/get-user-media-device-id.html

    r266166 r271471  
    2626            }).then(devices => {
    2727                devices.forEach((device) => {
     28                    if (device.kind == "audiooutput")
     29                        return;
    2830                    let kind = device.kind == "audioinput" ? "audio" : "video";
    2931                    deviceIds.push({ type: kind, id : device.deviceId});
  • trunk/Source/WebCore/ChangeLog

    r271470 r271471  
     12021-01-13  Jer Noble  <jer.noble@apple.com>
     2
     3        [HANG] 496ms to 1360ms in WebCore::AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices()
     4        https://bugs.webkit.org/show_bug.cgi?id=220471
     5
     6        Reviewed by Youenn Fablet.
     7
     8        Refactor RealtimeMediaSourceCenter::getMediaStreamDevices() to take a completion handler, rather than
     9        synchronously return a Vector of CaptureDevices. This also requires all CaptureDeviceManager subclasses
     10        to support taking a completion handler themselves. By default, all CaptureDeviceManagers will support
     11        the CompletionHandler path by just synchronously calling the completion handler with the existing
     12        synchronous method. But for AVAudioSessionCaptureDeviceManager, override that default implementation by
     13        activating the AVAudioSession on a background thread, and querying that session's inputs on a background
     14        thread as well.
     15
     16        * platform/mediastream/CaptureDeviceManager.h:
     17        * platform/mediastream/RealtimeMediaSourceCenter.cpp:
     18        (WebCore::RealtimeMediaSourceCenter::getMediaStreamDevices):
     19        * platform/mediastream/RealtimeMediaSourceCenter.h:
     20        * platform/mediastream/RealtimeMediaSourceFactory.h:
     21        (WebCore::AudioCaptureFactory::getSpeakerDevices const):
     22        * platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.h:
     23        * platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm:
     24        (WebCore::AVAudioSessionCaptureDeviceManager::audioSessionDeviceWithUID):
     25        (WebCore::AVAudioSessionCaptureDeviceManager::scheduleUpdateCaptureDevices):
     26        (WebCore::AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices):
     27        (WebCore::AVAudioSessionCaptureDeviceManager::getCaptureDevices):
     28        (WebCore::AVAudioSessionCaptureDeviceManager::activateAudioSession):
     29        (WebCore::AVAudioSessionCaptureDeviceManager::retrieveAudioSessionCaptureDevices const):
     30        (WebCore::AVAudioSessionCaptureDeviceManager::setAudioCaptureDevices):
     31        (WebCore::AVAudioSessionCaptureDeviceManager::audioSessionCaptureDevices): Deleted.
     32
    1332021-01-13  Jer Noble  <jer.noble@apple.com>
    234
  • trunk/Source/WebCore/platform/mediastream/CaptureDeviceManager.h

    r249002 r271471  
    3636public:
    3737    virtual const Vector<CaptureDevice>& captureDevices() = 0;
     38    virtual void getCaptureDevices(CompletionHandler<void(Vector<CaptureDevice>&&)>&& callback) { callback(copyToVector(captureDevices())); };
    3839    virtual Optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType, const String&) { return WTF::nullopt; }
    3940
  • trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp

    r266166 r271471  
    113113}
    114114
    115 Vector<CaptureDevice> RealtimeMediaSourceCenter::getMediaStreamDevices()
    116 {
    117     Vector<CaptureDevice> result;
    118     for (auto& device : audioCaptureFactory().audioCaptureDeviceManager().captureDevices()) {
    119         if (device.enabled())
    120             result.append(device);
    121     }
    122     for (auto& device : audioCaptureFactory().speakerDevices()) {
    123         if (device.enabled())
    124             result.append(device);
    125     }
    126     for (auto& device : videoCaptureFactory().videoCaptureDeviceManager().captureDevices()) {
    127         if (device.enabled())
    128             result.append(device);
    129     }
    130     for (auto& device : displayCaptureFactory().displayCaptureDeviceManager().captureDevices()) {
    131         if (device.enabled())
    132             result.append(device);
    133     }
    134 
    135     return result;
     115void RealtimeMediaSourceCenter::getMediaStreamDevices(CompletionHandler<void(Vector<CaptureDevice>&&)>&& completion)
     116{
     117    class CaptureDeviceAccumulator : public RefCounted<CaptureDeviceAccumulator> {
     118    public:
     119        static Ref<CaptureDeviceAccumulator> create(CompletionHandler<void(Vector<CaptureDevice>&&)>&& completion)
     120        {
     121            return adoptRef(*new CaptureDeviceAccumulator(WTFMove(completion)));
     122        }
     123
     124        ~CaptureDeviceAccumulator()
     125        {
     126            m_completionHandler(WTFMove(m_results));
     127        }
     128
     129        CompletionHandler<void(Vector<CaptureDevice>&&)> accumulate()
     130        {
     131            return [this, protectedThis = makeRef(*this)] (Vector<CaptureDevice>&& result) {
     132                m_results.appendVector(WTFMove(result));
     133            };
     134        }
     135
     136    private:
     137        explicit CaptureDeviceAccumulator(CompletionHandler<void(Vector<CaptureDevice>&&)>&& completion)
     138            : m_completionHandler(WTFMove(completion))
     139        {
     140        }
     141
     142        CompletionHandler<void(Vector<CaptureDevice>&&)> m_completionHandler;
     143        Vector<CaptureDevice> m_results;
     144    };
     145
     146    auto accumulator = CaptureDeviceAccumulator::create([completion = WTFMove(completion)] (auto&& devices) mutable {
     147        devices.removeAllMatching([] (auto& captureDevice) {
     148            return !captureDevice.enabled();
     149        });
     150        completion(WTFMove(devices));
     151    });
     152
     153    audioCaptureFactory().audioCaptureDeviceManager().getCaptureDevices(accumulator->accumulate());
     154    videoCaptureFactory().videoCaptureDeviceManager().getCaptureDevices(accumulator->accumulate());
     155    displayCaptureFactory().displayCaptureDeviceManager().getCaptureDevices(accumulator->accumulate());
     156    audioCaptureFactory().getSpeakerDevices(accumulator->accumulate());
    136157}
    137158
  • trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h

    r261373 r271471  
    6767    void createMediaStream(Ref<const Logger>&&, NewMediaStreamHandler&&, String&&, CaptureDevice&& audioDevice, CaptureDevice&& videoDevice, const MediaStreamRequest&);
    6868
    69     WEBCORE_EXPORT Vector<CaptureDevice> getMediaStreamDevices();
     69    WEBCORE_EXPORT void getMediaStreamDevices(CompletionHandler<void(Vector<CaptureDevice>&&)>&&);
    7070
    7171    const RealtimeMediaSourceSupportedConstraints& supportedConstraints() { return m_supportedConstraints; }
  • trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceFactory.h

    r271049 r271471  
    2828#if ENABLE(MEDIA_STREAM)
    2929
     30#include <wtf/CompletionHandler.h>
    3031#include <wtf/WeakPtr.h>
    3132#include <wtf/text/WTFString.h>
     
    6364    virtual CaptureDeviceManager& audioCaptureDeviceManager() = 0;
    6465    virtual const Vector<CaptureDevice>& speakerDevices() const = 0;
     66    virtual void getSpeakerDevices(CompletionHandler<void(Vector<CaptureDevice>&&)>&& completion) const { completion(copyToVector(speakerDevices())); }
    6567
    6668    class ExtensiveObserver : public CanMakeWeakPtr<ExtensiveObserver> { };
  • trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.h

    r271049 r271471  
    4949
    5050    const Vector<CaptureDevice>& captureDevices() final;
     51    void getCaptureDevices(CompletionHandler<void(Vector<CaptureDevice>&&)>&&) final;
    5152    const Vector<CaptureDevice>& speakerDevices() const { return m_speakerDevices; }
    5253    Optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType, const String&);
     
    6465
    6566    void createAudioSession();
     67    void activateAudioSession();
    6668    void refreshAudioCaptureDevices();
    67     Vector<AVAudioSessionCaptureDevice>& audioSessionCaptureDevices();
     69    Vector<AVAudioSessionCaptureDevice> retrieveAudioSessionCaptureDevices() const;
     70    void setAudioCaptureDevices(Vector<AVAudioSessionCaptureDevice>&&);
    6871
    6972    enum class AudioSessionState { NotNeeded, Inactive, Active };
  • trunk/Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm

    r271049 r271471  
    137137}
    138138
    139 Vector<AVAudioSessionCaptureDevice>& AVAudioSessionCaptureDeviceManager::audioSessionCaptureDevices()
     139Optional<AVAudioSessionCaptureDevice> AVAudioSessionCaptureDeviceManager::audioSessionDeviceWithUID(const String& deviceID)
    140140{
    141141    if (!m_audioSessionCaptureDevices)
    142142        refreshAudioCaptureDevices();
    143     return m_audioSessionCaptureDevices.value();
    144 }
    145 
    146 Optional<AVAudioSessionCaptureDevice> AVAudioSessionCaptureDeviceManager::audioSessionDeviceWithUID(const String& deviceID)
    147 {
    148     for (auto& device : audioSessionCaptureDevices()) {
     143
     144    for (auto& device : *m_audioSessionCaptureDevices) {
    149145        if (device.persistentId() == deviceID)
    150146            return device;
     
    155151void AVAudioSessionCaptureDeviceManager::scheduleUpdateCaptureDevices()
    156152{
    157     if (m_updateDeviceStateQueue.hasPendingTasks())
    158         return;
    159 
    160     m_updateDeviceStateQueue.enqueueTask([this] {
    161         refreshAudioCaptureDevices();
    162     });
     153    getCaptureDevices([] (auto) { });
    163154}
    164155
    165156void AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices()
    166157{
    167     {
    168         // Make sure we have created the audio session.
    169         auto locker = holdLock(m_lock);
    170     }
    171     bool firstTime = !m_devices;
    172158    if (m_audioSessionState == AudioSessionState::Inactive) {
    173159        m_audioSessionState = AudioSessionState::Active;
    174160
    175         if (!m_listener)
    176             m_listener = adoptNS([[WebAVAudioSessionAvailableInputsListener alloc] initWithCallback:this audioSession:m_audioSession.get()]);
    177 
    178         NSError *error = nil;
    179         [m_audioSession setActive:YES withOptions:0 error:&error];
    180         if (error)
    181             RELEASE_LOG_ERROR(WebRTC, "Failed to activate audio session with error: %@.", error.localizedDescription);
     161        dispatch_sync(m_dispatchQueue, makeBlockPtr([this] {
     162            activateAudioSession();
     163        }).get());
    182164    }
    183165
    184166    Vector<AVAudioSessionCaptureDevice> newAudioDevices;
    185     Vector<CaptureDevice> newDevices;
     167    dispatch_sync(m_dispatchQueue, makeBlockPtr([&] {
     168        newAudioDevices = retrieveAudioSessionCaptureDevices();
     169    }).get());
     170    setAudioCaptureDevices(WTFMove(newAudioDevices));
     171}
     172
     173void AVAudioSessionCaptureDeviceManager::getCaptureDevices(CompletionHandler<void(Vector<CaptureDevice>&&)>&& completion)
     174{
     175    if (m_audioSessionState == AudioSessionState::Inactive) {
     176        m_audioSessionState = AudioSessionState::Active;
     177
     178        dispatch_async(m_dispatchQueue, makeBlockPtr([this] {
     179            activateAudioSession();
     180        }).get());
     181    }
     182
     183    dispatch_async(m_dispatchQueue, makeBlockPtr([this, completion = WTFMove(completion)] () mutable {
     184        auto newAudioDevices = retrieveAudioSessionCaptureDevices();
     185        callOnWebThreadOrDispatchAsyncOnMainThread(makeBlockPtr([this, completion = WTFMove(completion), newAudioDevices = WTFMove(newAudioDevices)] () mutable {
     186            setAudioCaptureDevices(WTFMove(newAudioDevices));
     187            completion(copyToVector(*m_devices));
     188        }).get());
     189    }).get());
     190}
     191
     192void AVAudioSessionCaptureDeviceManager::activateAudioSession()
     193{
     194    if (!m_listener)
     195        m_listener = adoptNS([[WebAVAudioSessionAvailableInputsListener alloc] initWithCallback:this audioSession:m_audioSession.get()]);
     196
     197    NSError *error = nil;
     198    [m_audioSession setActive:YES withOptions:0 error:&error];
     199    if (error)
     200        RELEASE_LOG_ERROR(WebRTC, "Failed to activate audio session with error: %@.", error.localizedDescription);
     201}
     202
     203Vector<AVAudioSessionCaptureDevice> AVAudioSessionCaptureDeviceManager::retrieveAudioSessionCaptureDevices() const
     204{
     205    Vector<AVAudioSessionCaptureDevice> newAudioDevices;
    186206    auto *defaultInput = [m_audioSession currentRoute].inputs.firstObject;
    187     for (AVAudioSessionPortDescription *portDescription in [m_audioSession availableInputs]) {
    188         auto audioDevice = AVAudioSessionCaptureDevice::create(portDescription, defaultInput);
    189         newDevices.append(audioDevice);
    190         newAudioDevices.append(WTFMove(audioDevice));
    191     }
    192 
     207    newAudioDevices.reserveInitialCapacity([m_audioSession availableInputs].count);
     208
     209    for (AVAudioSessionPortDescription *portDescription in [m_audioSession availableInputs])
     210        newAudioDevices.uncheckedAppend(AVAudioSessionCaptureDevice::create(portDescription, defaultInput));
     211
     212    return newAudioDevices;
     213}
     214
     215void AVAudioSessionCaptureDeviceManager::setAudioCaptureDevices(Vector<AVAudioSessionCaptureDevice>&& newAudioDevices)
     216{
     217    bool firstTime = !m_devices;
    193218    bool haveDeviceChanges = !m_devices || newAudioDevices.size() != m_devices->size();
    194219    if (!haveDeviceChanges) {
     
    204229        return;
    205230
     231    auto newDevices = copyToVectorOf<CaptureDevice>(newAudioDevices);
    206232    m_audioSessionCaptureDevices = WTFMove(newAudioDevices);
    207233    std::sort(newDevices.begin(), newDevices.end(), [] (auto& first, auto& second) -> bool {
  • trunk/Source/WebKit/ChangeLog

    r271469 r271471  
     12021-01-13  Jer Noble  <jer.noble@apple.com>
     2
     3        [HANG] 496ms to 1360ms in WebCore::AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices()
     4        https://bugs.webkit.org/show_bug.cgi?id=220471
     5
     6        Reviewed by Youenn Fablet.
     7
     8        Use the completion-handler version of RealtimeMediaSourceCenter::getMediaStreamDevices().
     9
     10        * UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
     11        (WebKit::UserMediaPermissionRequestManagerProxy::computeFilteredDeviceList):
     12        (WebKit::UserMediaPermissionRequestManagerProxy::enumerateMediaDevicesForFrame):
     13        * UIProcess/UserMediaPermissionRequestManagerProxy.h:
     14        * UIProcess/UserMediaProcessManager.cpp:
     15        (WebKit::UserMediaProcessManager::updateCaptureDevices):
     16        (WebKit::UserMediaProcessManager::beginMonitoringCaptureDevices):
     17        * UIProcess/UserMediaProcessManager.h:
     18
    1192021-01-13  Per Arne Vollan  <pvollan@apple.com>
    220
  • trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp

    r271396 r271471  
    660660}
    661661
    662 Vector<CaptureDevice> UserMediaPermissionRequestManagerProxy::computeFilteredDeviceList(bool revealIdsAndLabels)
    663 {
    664     static const int defaultMaximumCameraCount = 1;
    665     static const int defaultMaximumMicrophoneCount = 1;
    666 
    667     auto devices = RealtimeMediaSourceCenter::singleton().getMediaStreamDevices();
    668     int cameraCount = 0;
    669     int microphoneCount = 0;
    670 
    671     Vector<CaptureDevice> filteredDevices;
    672     for (const auto& device : devices) {
    673         if (!device.enabled() || (device.type() != WebCore::CaptureDevice::DeviceType::Camera && device.type() != WebCore::CaptureDevice::DeviceType::Microphone && device.type() != WebCore::CaptureDevice::DeviceType::Speaker))
    674             continue;
    675 
    676         if (!revealIdsAndLabels) {
    677             if (device.type() == WebCore::CaptureDevice::DeviceType::Camera && ++cameraCount > defaultMaximumCameraCount)
     662void UserMediaPermissionRequestManagerProxy::computeFilteredDeviceList(bool revealIdsAndLabels, CompletionHandler<void(Vector<CaptureDevice>&&)>&& completion)
     663{
     664    static const unsigned defaultMaximumCameraCount = 1;
     665    static const unsigned defaultMaximumMicrophoneCount = 1;
     666
     667    RealtimeMediaSourceCenter::singleton().getMediaStreamDevices([this, weakThis = makeWeakPtr(this), revealIdsAndLabels, completion = WTFMove(completion)] (auto&& devices) mutable {
     668        unsigned cameraCount = 0;
     669        unsigned microphoneCount = 0;
     670
     671        Vector<CaptureDevice> filteredDevices;
     672        for (const auto& device : devices) {
     673            if (!device.enabled() || (device.type() != WebCore::CaptureDevice::DeviceType::Camera && device.type() != WebCore::CaptureDevice::DeviceType::Microphone && device.type() != WebCore::CaptureDevice::DeviceType::Speaker))
    678674                continue;
    679             if (device.type() == WebCore::CaptureDevice::DeviceType::Microphone && ++microphoneCount > defaultMaximumMicrophoneCount)
    680                 continue;
    681             if (device.type() != WebCore::CaptureDevice::DeviceType::Camera && device.type() != WebCore::CaptureDevice::DeviceType::Microphone)
    682                 continue;
    683         } else {
    684             // We only expose speakers tied to a microphone for the moment.
    685             if (device.type() == WebCore::CaptureDevice::DeviceType::Speaker && !haveMicrophoneDevice(devices, device.groupId()))
    686                 continue;
     675
     676            if (!revealIdsAndLabels) {
     677                if (device.type() == WebCore::CaptureDevice::DeviceType::Camera && ++cameraCount > defaultMaximumCameraCount)
     678                    continue;
     679                if (device.type() == WebCore::CaptureDevice::DeviceType::Microphone && ++microphoneCount > defaultMaximumMicrophoneCount)
     680                    continue;
     681                if (device.type() != WebCore::CaptureDevice::DeviceType::Camera && device.type() != WebCore::CaptureDevice::DeviceType::Microphone)
     682                    continue;
     683            } else {
     684                // We only expose speakers tied to a microphone for the moment.
     685                if (device.type() == WebCore::CaptureDevice::DeviceType::Speaker && !haveMicrophoneDevice(devices, device.groupId()))
     686                    continue;
     687            }
     688
     689            filteredDevices.append(revealIdsAndLabels ? device : CaptureDevice({ }, device.type(), { }, { }));
    687690        }
    688691
    689         filteredDevices.append(revealIdsAndLabels ? device : CaptureDevice({ }, device.type(), { }, { }));
    690     }
    691 
    692     m_hasFilteredDeviceList = !revealIdsAndLabels;
    693 
    694     ALWAYS_LOG(LOGIDENTIFIER, filteredDevices.size(), " devices revealed");
    695     return filteredDevices;
     692        if (weakThis)
     693            m_hasFilteredDeviceList = !revealIdsAndLabels;
     694
     695        ALWAYS_LOG(LOGIDENTIFIER, filteredDevices.size(), " devices revealed");
     696        completion(WTFMove(filteredDevices));
     697    });
    696698}
    697699#endif
     
    745747
    746748            callCompletionHandler.release();
    747             completionHandler(computeFilteredDeviceList(revealIdsAndLabels), deviceIDHashSalt);
     749            computeFilteredDeviceList(revealIdsAndLabels, [completionHandler = WTFMove(completionHandler), deviceIDHashSalt = WTFMove(deviceIDHashSalt)] (auto&& devices) mutable {
     750                completionHandler(devices, deviceIDHashSalt);
     751            });
    748752        });
    749753    };
  • trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h

    r271396 r271471  
    121121    bool wasGrantedVideoOrAudioAccess(WebCore::FrameIdentifier, const WebCore::SecurityOrigin& userMediaDocumentOrigin, const WebCore::SecurityOrigin& topLevelDocumentOrigin);
    122122
    123     Vector<WebCore::CaptureDevice> computeFilteredDeviceList(bool revealIdsAndLabels);
     123    void computeFilteredDeviceList(bool revealIdsAndLabels, CompletionHandler<void(Vector<WebCore::CaptureDevice>&&)>&&);
    124124
    125125    void processUserMediaPermissionRequest();
  • trunk/Source/WebKit/UIProcess/UserMediaProcessManager.cpp

    r271154 r271471  
    218218}
    219219
     220void UserMediaProcessManager::updateCaptureDevices(ShouldNotify shouldNotify)
     221{
     222    WebCore::RealtimeMediaSourceCenter::singleton().getMediaStreamDevices([this, shouldNotify] (auto&& newDevices) mutable {
     223        auto oldDevices = WTFMove(m_captureDevices);
     224        m_captureDevices = WTFMove(newDevices);
     225
     226        if (shouldNotify == ShouldNotify::No)
     227            return;
     228
     229        if (m_captureDevices.size() == oldDevices.size()) {
     230            bool haveChanges = false;
     231            for (auto &newDevice : m_captureDevices) {
     232                if (newDevice.type() != WebCore::CaptureDevice::DeviceType::Camera && newDevice.type() != WebCore::CaptureDevice::DeviceType::Microphone)
     233                    continue;
     234
     235                auto index = oldDevices.findMatching([&newDevice] (auto& oldDevice) {
     236                    return newDevice.persistentId() == oldDevice.persistentId() && newDevice.enabled() != oldDevice.enabled();
     237                });
     238
     239                if (index == notFound) {
     240                    haveChanges = true;
     241                    break;
     242                }
     243            }
     244
     245            if (!haveChanges)
     246                return;
     247        }
     248
     249        // When a device with camera and microphone is attached or detached, the CaptureDevice notification for
     250        // the different devices won't arrive at the same time so delay a bit so we can coalesce the callbacks.
     251        if (!m_debounceTimer.isActive())
     252            m_debounceTimer.startOneShot(deviceChangeDebounceTimerInterval);
     253    });
     254}
     255
    220256void UserMediaProcessManager::beginMonitoringCaptureDevices()
    221257{
     
    223259
    224260    std::call_once(onceFlag, [this] {
    225         m_captureDevices = WebCore::RealtimeMediaSourceCenter::singleton().getMediaStreamDevices();
     261        updateCaptureDevices(ShouldNotify::No);
    226262
    227263        WebCore::RealtimeMediaSourceCenter::singleton().setDevicesChangedObserver([this]() {
    228             auto oldDevices = WTFMove(m_captureDevices);
    229             m_captureDevices = WebCore::RealtimeMediaSourceCenter::singleton().getMediaStreamDevices();
    230 
    231             if (m_captureDevices.size() == oldDevices.size()) {
    232                 bool haveChanges = false;
    233                 for (auto &newDevice : m_captureDevices) {
    234                     if (newDevice.type() != WebCore::CaptureDevice::DeviceType::Camera && newDevice.type() != WebCore::CaptureDevice::DeviceType::Microphone)
    235                         continue;
    236 
    237                     auto index = oldDevices.findMatching([&newDevice] (auto& oldDevice) {
    238                         return newDevice.persistentId() == oldDevice.persistentId() && newDevice.enabled() != oldDevice.enabled();
    239                     });
    240 
    241                     if (index == notFound) {
    242                         haveChanges = true;
    243                         break;
    244                     }
    245                 }
    246 
    247                 if (!haveChanges)
    248                     return;
    249             }
    250 
    251             // When a device with camera and microphone is attached or detached, the CaptureDevice notification for
    252             // the different devices won't arrive at the same time so delay a bit so we can coalesce the callbacks.
    253             if (!m_debounceTimer.isActive())
    254                 m_debounceTimer.startOneShot(deviceChangeDebounceTimerInterval);
     264            updateCaptureDevices(ShouldNotify::Yes);
    255265        });
    256266    });
  • trunk/Source/WebKit/UIProcess/UserMediaProcessManager.h

    r271154 r271471  
    4949
    5050private:
     51    enum class ShouldNotify { Yes, No };
     52    void updateCaptureDevices(ShouldNotify);
    5153    void captureDevicesChanged();
    5254
Note: See TracChangeset for help on using the changeset viewer.