Changeset 215929 in webkit


Ignore:
Timestamp:
Apr 28, 2017 10:22:19 AM (7 years ago)
Author:
eric.carlson@apple.com
Message:

Implement ondevicechange
https://bugs.webkit.org/show_bug.cgi?id=169872
<rdar://problem/28945035>

Reviewed by Jer Noble.

Source/WebCore:

Test: fast/mediastream/device-change-event.html

  • Modules/mediastream/MediaDevices.cpp:

(WebCore::MediaDevices::MediaDevices): Register for devicechange callbacks.
(WebCore::MediaDevices::~MediaDevices): Unregister.
(WebCore::MediaDevices::scheduledEventTimerFired):

  • Modules/mediastream/MediaDevices.h:
  • Modules/mediastream/MediaDevices.idl:
  • Modules/mediastream/MediaDevicesEnumerationRequest.cpp:

(WebCore::MediaDevicesEnumerationRequest::setDeviceInfo): Remove unnecessary instance variables.

  • Modules/mediastream/MediaDevicesEnumerationRequest.h:
  • Modules/mediastream/MediaDevicesRequest.cpp:

(WebCore::MediaDevicesRequest::start): Remove m_idHashSalt, it isn't used. RealtimeMediaSourceCenter
now has the method to hash ids and group IDs.
(WebCore::hashString): Deleted.
(WebCore::MediaDevicesRequest::hashID): Deleted.

  • Modules/mediastream/MediaDevicesRequest.h:
  • dom/Document.h:

(WebCore::Document::setDeviceIDHashSalt):
(WebCore::Document::deviceIDHashSalt):

  • dom/EventNames.h: Add devicechange.
  • dom/EventTargetFactory.in: Add MediaDevices.
  • html/HTMLAttributeNames.in: Add ondevicechange.
  • platform/mediastream/CaptureDeviceManager.cpp:

(WebCore::CaptureDeviceManager::captureDeviceFromPersistentID): Renamed from captureDeviceFromDeviceID
and changed to return a std::optional<CaptureDevice>.
(WebCore::CaptureDeviceManager::captureDeviceFromDeviceID): Deleted.

  • platform/mediastream/RealtimeMediaSourceCenter.cpp:

(WebCore::addStringToSHA): New, add string bytes to SHA1. Moved from MediaDevicesRequest
so we can use for in testing.
(WebCore::RealtimeMediaSourceCenter::hashStringWithSalt): Generate hash for a string with a
salt. Moved from MediaDevicesRequest so we can use for in testing.
(WebCore::RealtimeMediaSourceCenter::captureDeviceWithUniqueID): Find a CaptureDevice given
a unique ID and the process hash salt.
(WebCore::RealtimeMediaSourceCenter::setDeviceEnabled): Enable/disable a device. Used for
layout tests only.
(WebCore::RealtimeMediaSourceCenter::addDevicesChangedObserver): Add a devices changed listener.
(WebCore::RealtimeMediaSourceCenter::removeDevicesChangedObserver): Remove a listener.
(WebCore::RealtimeMediaSourceCenter::captureDevicesChanged): Notify listeners.

  • platform/mediastream/RealtimeMediaSourceCenter.h:
  • platform/mediastream/mac/AVCaptureDeviceManager.mm:

(WebCore::AVCaptureDeviceManager::addDevicesChangedObserver): Update for change to captureDeviceFromDeviceID.

  • platform/mock/MockRealtimeMediaSource.cpp:

(WebCore::MockRealtimeMediaSource::audioDevices): All devices are enabled by default.
(WebCore::MockRealtimeMediaSource::videoDevices): Ditto.

  • platform/mock/MockRealtimeMediaSourceCenter.cpp:

(WebCore::MockRealtimeMediaSourceCenter::createMediaStream): Drive-by cleanup: use the vector
of devices instead of making assumptions about the number.
(WebCore::MockRealtimeMediaSourceCenter::getMediaStreamDevices): Only include enabled devices.
(WebCore::MockRealtimeMediaSourceCenter::setDeviceEnabled): Enable or disable a device.

  • platform/mock/MockRealtimeMediaSourceCenter.h:
  • testing/Internals.cpp:

(WebCore::Internals::setMediaDeviceState): Enable or disable a mock capture device.

  • testing/Internals.h:
  • testing/Internals.idl:

LayoutTests:

  • fast/mediastream/device-change-event-expected.txt: Added.
  • fast/mediastream/device-change-event.html: Added.
Location:
trunk
Files:
2 added
25 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r215927 r215929  
     12017-04-28  Eric Carlson  <eric.carlson@apple.com>
     2
     3        Implement ondevicechange
     4        https://bugs.webkit.org/show_bug.cgi?id=169872
     5        <rdar://problem/28945035>
     6
     7        Reviewed by Jer Noble.
     8
     9        * fast/mediastream/device-change-event-expected.txt: Added.
     10        * fast/mediastream/device-change-event.html: Added.
     11
    1122017-04-28  Joanmarie Diggs  <jdiggs@igalia.com>
    213
  • trunk/Source/WebCore/ChangeLog

    r215928 r215929  
     12017-04-28  Eric Carlson  <eric.carlson@apple.com>
     2
     3        Implement ondevicechange
     4        https://bugs.webkit.org/show_bug.cgi?id=169872
     5        <rdar://problem/28945035>
     6
     7        Reviewed by Jer Noble.
     8
     9        Test: fast/mediastream/device-change-event.html
     10
     11        * Modules/mediastream/MediaDevices.cpp:
     12        (WebCore::MediaDevices::MediaDevices): Register for devicechange callbacks.
     13        (WebCore::MediaDevices::~MediaDevices): Unregister.
     14        (WebCore::MediaDevices::scheduledEventTimerFired):
     15        * Modules/mediastream/MediaDevices.h:
     16        * Modules/mediastream/MediaDevices.idl:
     17
     18        * Modules/mediastream/MediaDevicesEnumerationRequest.cpp:
     19        (WebCore::MediaDevicesEnumerationRequest::setDeviceInfo): Remove unnecessary instance variables.
     20        * Modules/mediastream/MediaDevicesEnumerationRequest.h:
     21
     22        * Modules/mediastream/MediaDevicesRequest.cpp:
     23        (WebCore::MediaDevicesRequest::start): Remove m_idHashSalt, it isn't used. RealtimeMediaSourceCenter
     24        now has the method to hash ids and group IDs.
     25        (WebCore::hashString): Deleted.
     26        (WebCore::MediaDevicesRequest::hashID): Deleted.
     27        * Modules/mediastream/MediaDevicesRequest.h:
     28
     29        * dom/Document.h:
     30        (WebCore::Document::setDeviceIDHashSalt):
     31        (WebCore::Document::deviceIDHashSalt):
     32
     33        * dom/EventNames.h: Add devicechange.
     34
     35        * dom/EventTargetFactory.in: Add MediaDevices.
     36
     37        * html/HTMLAttributeNames.in: Add ondevicechange.
     38
     39        * platform/mediastream/CaptureDeviceManager.cpp:
     40        (WebCore::CaptureDeviceManager::captureDeviceFromPersistentID): Renamed from captureDeviceFromDeviceID
     41        and changed to return a std::optional<CaptureDevice>.
     42        (WebCore::CaptureDeviceManager::captureDeviceFromDeviceID): Deleted.
     43
     44        * platform/mediastream/RealtimeMediaSourceCenter.cpp:
     45        (WebCore::addStringToSHA): New, add string bytes to SHA1. Moved from MediaDevicesRequest
     46        so we can use for in testing.
     47        (WebCore::RealtimeMediaSourceCenter::hashStringWithSalt): Generate hash for a string with a
     48        salt. Moved from MediaDevicesRequest so we can use for in testing.
     49        (WebCore::RealtimeMediaSourceCenter::captureDeviceWithUniqueID): Find a CaptureDevice given
     50        a unique ID and the process hash salt.
     51        (WebCore::RealtimeMediaSourceCenter::setDeviceEnabled): Enable/disable a device. Used for
     52        layout tests only.
     53        (WebCore::RealtimeMediaSourceCenter::addDevicesChangedObserver): Add a devices changed listener.
     54        (WebCore::RealtimeMediaSourceCenter::removeDevicesChangedObserver): Remove a listener.
     55        (WebCore::RealtimeMediaSourceCenter::captureDevicesChanged): Notify listeners.
     56        * platform/mediastream/RealtimeMediaSourceCenter.h:
     57
     58        * platform/mediastream/mac/AVCaptureDeviceManager.mm:
     59        (WebCore::AVCaptureDeviceManager::addDevicesChangedObserver): Update for change to captureDeviceFromDeviceID.
     60
     61        * platform/mock/MockRealtimeMediaSource.cpp:
     62        (WebCore::MockRealtimeMediaSource::audioDevices): All devices are enabled by default.
     63        (WebCore::MockRealtimeMediaSource::videoDevices): Ditto.
     64
     65        * platform/mock/MockRealtimeMediaSourceCenter.cpp:
     66        (WebCore::MockRealtimeMediaSourceCenter::createMediaStream): Drive-by cleanup: use the vector
     67        of devices instead of making assumptions about the number.
     68        (WebCore::MockRealtimeMediaSourceCenter::getMediaStreamDevices): Only include enabled devices.
     69        (WebCore::MockRealtimeMediaSourceCenter::setDeviceEnabled): Enable or disable a device.
     70        * platform/mock/MockRealtimeMediaSourceCenter.h:
     71
     72        * testing/Internals.cpp:
     73        (WebCore::Internals::setMediaDeviceState): Enable or disable a mock capture device.
     74        * testing/Internals.h:
     75        * testing/Internals.idl:
     76
    1772017-04-28  Alex Christensen  <achristensen@webkit.org>
    278
  • trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp

    r215703 r215929  
    11/*
    22 * Copyright (C) 2015 Ericsson AB. All rights reserved.
     3 * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    3536
    3637#include "Document.h"
     38#include "Event.h"
     39#include "EventNames.h"
    3740#include "MediaConstraintsImpl.h"
    3841#include "MediaDevicesRequest.h"
    3942#include "MediaTrackSupportedConstraints.h"
    40 #include "RealtimeMediaSourceCenter.h"
    4143#include "UserMediaRequest.h"
     44#include <wtf/RandomNumber.h>
    4245
    4346namespace WebCore {
     
    4548inline MediaDevices::MediaDevices(Document& document)
    4649    : ContextDestructionObserver(&document)
     50    , m_scheduledEventTimer(*this, &MediaDevices::scheduledEventTimerFired)
    4751{
     52    m_deviceChangedToken = RealtimeMediaSourceCenter::singleton().addDevicesChangedObserver([this]() {
     53
     54        // FIXME: We should only dispatch an event if the user has been granted access to the type of
     55        // device that was added or removed.
     56        if (!m_scheduledEventTimer.isActive())
     57            m_scheduledEventTimer.startOneShot(Seconds(randomNumber() / 2));
     58    });
     59}
     60
     61MediaDevices::~MediaDevices()
     62{
     63    if (m_deviceChangedToken)
     64        RealtimeMediaSourceCenter::singleton().removeDevicesChangedObserver(m_deviceChangedToken);
    4865}
    4966
     
    109126}
    110127
     128void MediaDevices::scheduledEventTimerFired()
     129{
     130    dispatchEvent(Event::create(eventNames().devicechangeEvent, false, false));
     131}
     132
    111133} // namespace WebCore
    112134
  • trunk/Source/WebCore/Modules/mediastream/MediaDevices.h

    r209959 r215929  
    3434#if ENABLE(MEDIA_STREAM)
    3535
     36#include "EventTarget.h"
    3637#include "ExceptionOr.h"
    3738#include "JSDOMPromise.h"
    3839#include "MediaTrackConstraints.h"
     40#include "RealtimeMediaSourceCenter.h"
     41#include "Timer.h"
    3942
    4043namespace WebCore {
     
    4649struct MediaTrackSupportedConstraints;
    4750
    48 class MediaDevices : public ScriptWrappable, public RefCounted<MediaDevices>, public ContextDestructionObserver {
     51class MediaDevices : public RefCounted<MediaDevices>, public ContextDestructionObserver, public EventTargetWithInlineData {
    4952public:
    5053    static Ref<MediaDevices> create(Document&);
     54
     55    ~MediaDevices();
    5156
    5257    Document* document() const;
     
    6368    MediaTrackSupportedConstraints getSupportedConstraints();
    6469
     70    using RefCounted<MediaDevices>::ref;
     71    using RefCounted<MediaDevices>::deref;
     72
    6573private:
    6674    explicit MediaDevices(Document&);
     75
     76    void scheduledEventTimerFired();
     77
     78    // EventTargetWithInlineData.
     79    EventTargetInterface eventTargetInterface() const override { return MediaDevicesEventTargetInterfaceType; }
     80    ScriptExecutionContext* scriptExecutionContext() const final { return m_scriptExecutionContext; }
     81    void refEventTarget() override { ref(); }
     82    void derefEventTarget() override { deref(); }
     83
     84    Timer m_scheduledEventTimer;
     85    RealtimeMediaSourceCenter::DevicesChangedObserverToken m_deviceChangedToken { 0 };
    6786};
    6887
  • trunk/Source/WebCore/Modules/mediastream/MediaDevices.idl

    r214170 r215929  
    3434    NoInterfaceObject,
    3535] interface MediaDevices {
    36     // FIXME 169872: missing ondevicechange
     36    attribute EventHandler ondevicechange;
    3737    Promise<sequence<MediaDeviceInfo>> enumerateDevices();
    3838
  • trunk/Source/WebCore/Modules/mediastream/MediaDevicesEnumerationRequest.cpp

    r210923 r215929  
    100100void MediaDevicesEnumerationRequest::setDeviceInfo(const Vector<CaptureDevice>& deviceList, const String& deviceIdentifierHashSalt, bool originHasPersistentAccess)
    101101{
    102     m_deviceList = deviceList;
    103     m_deviceIdentifierHashSalt = deviceIdentifierHashSalt;
    104     m_originHasPersistentAccess = originHasPersistentAccess;
    105 
    106102    if (m_completionHandler)
    107         m_completionHandler(m_deviceList, m_deviceIdentifierHashSalt, m_originHasPersistentAccess);
     103        m_completionHandler(deviceList, deviceIdentifierHashSalt, originHasPersistentAccess);
    108104    m_completionHandler = nullptr;
    109105}
  • trunk/Source/WebCore/Modules/mediastream/MediaDevicesEnumerationRequest.h

    r207463 r215929  
    6262
    6363    CompletionHandler m_completionHandler;
    64     Vector<CaptureDevice> m_deviceList;
    65     String m_deviceIdentifierHashSalt;
    66     bool m_originHasPersistentAccess { false };
    6764};
    6865
  • trunk/Source/WebCore/Modules/mediastream/MediaDevicesRequest.cpp

    r212418 r215929  
    3535#include "JSMediaDeviceInfo.h"
    3636#include "MediaDevicesEnumerationRequest.h"
     37#include "RealtimeMediaSourceCenter.h"
    3738#include "SecurityOrigin.h"
    3839#include "UserMediaController.h"
     
    8788
    8889        Document& document = downcast<Document>(*scriptExecutionContext());
    89         UserMediaController* controller = UserMediaController::from(document.page());
    90         if (!controller)
    91             return;
    92 
    93         m_idHashSalt = deviceIdentifierHashSalt;
     90        document.setDeviceIDHashSalt(deviceIdentifierHashSalt);
    9491
    9592        Vector<RefPtr<MediaDeviceInfo>> devices;
     
    9996                label = deviceInfo.label();
    10097
    101             auto id = hashID(deviceInfo.persistentId());
     98            auto id = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(deviceInfo.persistentId(), deviceIdentifierHashSalt);
    10299            if (id.isEmpty())
    103100                continue;
    104101
    105             auto groupId = hashID(deviceInfo.groupId());
     102            auto groupId = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(deviceInfo.groupId(), deviceIdentifierHashSalt);
    106103            auto deviceType = deviceInfo.type() == CaptureDevice::DeviceType::Audio ? MediaDeviceInfo::Kind::Audioinput : MediaDeviceInfo::Kind::Videoinput;
    107104            devices.append(MediaDeviceInfo::create(scriptExecutionContext(), label, id, groupId, deviceType));
     
    117114}
    118115
    119 static void hashString(SHA1& sha1, const String& string)
    120 {
    121     if (string.isEmpty())
    122         return;
    123 
    124     if (string.is8Bit() && string.containsOnlyASCII()) {
    125         const uint8_t nullByte = 0;
    126         sha1.addBytes(string.characters8(), string.length());
    127         sha1.addBytes(&nullByte, 1);
    128         return;
    129     }
    130 
    131     auto utf8 = string.utf8();
    132     sha1.addBytes(reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length() + 1); // Include terminating null byte.
    133 }
    134 
    135 String MediaDevicesRequest::hashID(const String& id)
    136 {
    137     if (id.isEmpty() || m_idHashSalt.isEmpty())
    138         return emptyString();
    139 
    140     SHA1 sha1;
    141 
    142     hashString(sha1, id);
    143     hashString(sha1, m_idHashSalt);
    144 
    145     SHA1::Digest digest;
    146     sha1.computeHash(digest);
    147 
    148     return SHA1::hexDigest(digest).data();
    149 }
    150 
    151116} // namespace WebCore
    152117
  • trunk/Source/WebCore/Modules/mediastream/MediaDevicesRequest.h

    r208663 r215929  
    5252    void contextDestroyed() final;
    5353
    54     String hashID(const String&);
    55 
    5654    MediaDevices::EnumerateDevicesPromise m_promise;
    5755    RefPtr<MediaDevicesRequest> m_protector;
    5856    RefPtr<MediaDevicesEnumerationRequest> m_enumerationRequest;
    59 
    60     String m_idHashSalt;
    6157};
    6258
  • trunk/Source/WebCore/Modules/mediastream/UserMediaController.h

    r208646 r215929  
    4747    void cancelMediaDevicesEnumerationRequest(MediaDevicesEnumerationRequest&);
    4848
     49    void setDeviceIDHashSalt(const String& salt) { m_idHashSalt = salt; }
     50    String deviceIDHashSalt() const { return m_idHashSalt; }
     51
    4952    WEBCORE_EXPORT static const char* supplementName();
    5053    static UserMediaController* from(Page* page) { return static_cast<UserMediaController*>(Supplement<Page>::from(page, supplementName())); }
     
    5255private:
    5356    UserMediaClient* m_client;
     57    String m_idHashSalt;
    5458};
    5559
  • trunk/Source/WebCore/dom/Document.h

    r215797 r215929  
    12751275    void setHasActiveMediaStreamTrack() { m_hasHadActiveMediaStreamTrack = true; }
    12761276    bool hasHadActiveMediaStreamTrack() const { return m_hasHadActiveMediaStreamTrack; }
     1277    void setDeviceIDHashSalt(const String& salt) { m_idHashSalt = salt; }
     1278    String deviceIDHashSalt() const { return m_idHashSalt; }
    12771279#endif
    12781280
     
    17491751
    17501752#if ENABLE(MEDIA_STREAM)
     1753    String m_idHashSalt;
    17511754    bool m_hasHadActiveMediaStreamTrack { false };
    17521755#endif
  • trunk/Source/WebCore/dom/EventNames.h

    r215916 r215929  
    9292    macro(datachannel) \
    9393    macro(dblclick) \
     94    macro(devicechange) \
    9495    macro(devicemotion) \
    9596    macro(deviceorientation) \
  • trunk/Source/WebCore/dom/EventTargetFactory.in

    r214536 r215929  
    1616IDBTransaction conditional=INDEXED_DATABASE
    1717MediaController conditional=VIDEO
     18MediaDevices conditional=MEDIA_STREAM
    1819MediaKeySession conditional=ENCRYPTED_MEDIA
    1920MediaRemoteControls conditional=MEDIA_SESSION
  • trunk/Source/WebCore/html/HTMLAttributeNames.in

    r215233 r215929  
    203203oncut
    204204ondblclick
     205ondevicechange
    205206ondrag
    206207ondragend
  • trunk/Source/WebCore/platform/mediastream/CaptureDeviceManager.cpp

    r215922 r215929  
    7070}
    7171
    72 bool CaptureDeviceManager::captureDeviceFromDeviceID(const String& captureDeviceID, CaptureDevice& foundDevice)
     72std::optional<CaptureDevice> CaptureDeviceManager::captureDeviceFromPersistentID(const String& captureDeviceID)
    7373{
    7474    for (auto& device : captureDevices()) {
    75         if (device.persistentId() == captureDeviceID) {
    76             foundDevice = device;
    77             return true;
    78         }
     75        if (device.persistentId() == captureDeviceID)
     76            return device;
    7977    }
    8078
    81     return false;
     79    return std::nullopt;
    8280}
     81
     82#if 0
     83std::optional<CaptureDevice> CaptureDeviceManager::captureDeviceFromPersistentID(const String& captureDeviceID, const String& idHashSalt)
     84{
     85    for (auto& device : captureDevices()) {
     86        auto hashedID = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(device.persistentId(), idHashSalt);
     87        if (device.persistentId() == captureDeviceID)
     88            return device;
     89    }
     90
     91    return std::nullopt;
     92}
     93
     94for (auto& captureDevice : getMediaStreamDevices()) {
     95    auto hashedID = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(captureDevice.persistentId(), idHashSalt);
     96    if (hashedID == uniqueID)
     97        return String { captureDevice.persistentId() };
     98}
     99
     100return Exception { NOT_FOUND_ERR };
     101
     102#endif
    83103
    84104std::optional<CaptureDevice> CaptureDeviceManager::deviceWithUID(const String& deviceUID, RealtimeMediaSource::Type type)
  • trunk/Source/WebCore/platform/mediastream/CaptureDeviceManager.h

    r215418 r215929  
    4343protected:
    4444    virtual ~CaptureDeviceManager();
    45     bool captureDeviceFromDeviceID(const String& captureDeviceID, CaptureDevice& source);
     45    std::optional<CaptureDevice> captureDeviceFromPersistentID(const String& captureDeviceID);
    4646};
    4747
  • trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp

    r215418 r215929  
    3131
    3232#include "config.h"
     33#include "RealtimeMediaSourceCenter.h"
    3334
    3435#if ENABLE(MEDIA_STREAM)
    35 #include "RealtimeMediaSourceCenter.h"
    3636
    3737#include "MediaStreamPrivate.h"
     38#include <wtf/SHA1.h>
    3839
    3940namespace WebCore {
     
    110111        m_videoCaptureDeviceManager = nullptr;
    111112}
     113
     114static void addStringToSHA1(SHA1& sha1, const String& string)
     115{
     116    if (string.isEmpty())
     117        return;
     118
     119    if (string.is8Bit() && string.containsOnlyASCII()) {
     120        const uint8_t nullByte = 0;
     121        sha1.addBytes(string.characters8(), string.length());
     122        sha1.addBytes(&nullByte, 1);
     123        return;
     124    }
     125
     126    auto utf8 = string.utf8();
     127    sha1.addBytes(reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length() + 1); // Include terminating null byte.
     128}
     129
     130String RealtimeMediaSourceCenter::hashStringWithSalt(const String& id, const String& hashSalt)
     131{
     132    if (id.isEmpty() || hashSalt.isEmpty())
     133        return emptyString();
     134
     135    SHA1 sha1;
     136
     137    addStringToSHA1(sha1, id);
     138    addStringToSHA1(sha1, hashSalt);
    112139   
     140    SHA1::Digest digest;
     141    sha1.computeHash(digest);
     142   
     143    return SHA1::hexDigest(digest).data();
     144}
     145
     146std::optional<CaptureDevice> RealtimeMediaSourceCenter::captureDeviceWithUniqueID(const String& uniqueID, const String& idHashSalt)
     147{
     148    for (auto& device : getMediaStreamDevices()) {
     149        if (uniqueID == hashStringWithSalt(device.persistentId(), idHashSalt))
     150            return device;
     151    }
     152
     153    return std::nullopt;
     154}
     155
     156ExceptionOr<void> RealtimeMediaSourceCenter::setDeviceEnabled(const String&, bool)
     157{
     158    return Exception { NOT_FOUND_ERR, ASCIILiteral("Not implemented!") };
     159}
     160
     161RealtimeMediaSourceCenter::DevicesChangedObserverToken RealtimeMediaSourceCenter::addDevicesChangedObserver(std::function<void()>&& observer)
     162{
     163    DevicesChangedObserverToken nextToken = 0;
     164    m_devicesChangedObservers.set(++nextToken, WTFMove(observer));
     165    return nextToken;
     166}
     167
     168void RealtimeMediaSourceCenter::removeDevicesChangedObserver(DevicesChangedObserverToken token)
     169{
     170    bool wasRemoved = m_devicesChangedObservers.remove(token);
     171    ASSERT_UNUSED(wasRemoved, wasRemoved);
     172}
     173
     174void RealtimeMediaSourceCenter::captureDevicesChanged()
     175{
     176    auto callbacks = m_devicesChangedObservers;
     177    for (auto it : callbacks)
     178        it.value();
     179}
     180
    113181} // namespace WebCore
    114182
  • trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h

    r215418 r215929  
    3030 */
    3131
    32 #ifndef RealtimeMediaSourceCenter_h
    33 #define RealtimeMediaSourceCenter_h
     32#pragma once
    3433
    3534#if ENABLE(MEDIA_STREAM)
    3635
     36#include "ExceptionOr.h"
    3737#include "RealtimeMediaSource.h"
    3838#include "RealtimeMediaSourceSupportedConstraints.h"
     
    8989    CaptureDeviceManager* videoCaptureDeviceManager() const { return m_videoCaptureDeviceManager; }
    9090
     91    String hashStringWithSalt(const String& id, const String& hashSalt);
     92    WEBCORE_EXPORT std::optional<CaptureDevice> captureDeviceWithUniqueID(const String& id, const String& hashSalt);
     93    virtual ExceptionOr<void> setDeviceEnabled(const String&, bool);
     94
     95    using DevicesChangedObserverToken = unsigned;
     96    DevicesChangedObserverToken addDevicesChangedObserver(std::function<void()>&&);
     97    void removeDevicesChangedObserver(DevicesChangedObserverToken);
     98    void captureDevicesChanged();
     99
    91100protected:
    92101    RealtimeMediaSourceCenter();
     
    100109    CaptureDeviceManager* m_audioCaptureDeviceManager { nullptr };
    101110    CaptureDeviceManager* m_videoCaptureDeviceManager { nullptr };
     111
     112    HashMap<unsigned, std::function<void()>> m_devicesChangedObservers;
    102113};
    103114
     
    106117#endif // ENABLE(MEDIA_STREAM)
    107118
    108 #endif // RealtimeMediaSourceCenter_h
  • trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.mm

    r215922 r215929  
    132132            continue;
    133133
    134         CaptureDevice existingCaptureDevice;
    135         if (captureDeviceFromDeviceID(platformDevice.uniqueID, existingCaptureDevice) && existingCaptureDevice.type() == type)
     134        std::optional<CaptureDevice> existingCaptureDevice = captureDeviceFromPersistentID(platformDevice.uniqueID);
     135        if (existingCaptureDevice && existingCaptureDevice->type() == type)
    136136            continue;
    137137
  • trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp

    r215362 r215929  
    4949    static NeverDestroyed<Vector<CaptureDevice>> info;
    5050    if (!info.get().size()) {
    51         info.get().append(CaptureDevice("239c24b0-2b15-11e3-8224-0800200c9a66", CaptureDevice::DeviceType::Audio, "Mock audio device 1"));
    52         info.get().append(CaptureDevice("239c24b1-2b15-11e3-8224-0800200c9a66", CaptureDevice::DeviceType::Audio, "Mock audio device 2"));
     51        auto captureDevice = CaptureDevice("239c24b0-2b15-11e3-8224-0800200c9a66", CaptureDevice::DeviceType::Audio, "Mock audio device 1");
     52        captureDevice.setEnabled(true);
     53        info.get().append(captureDevice);
     54
     55        captureDevice = CaptureDevice("239c24b1-2b15-11e3-8224-0800200c9a66", CaptureDevice::DeviceType::Audio, "Mock audio device 2");
     56        captureDevice.setEnabled(true);
     57        info.get().append(captureDevice);
    5358    }
    5459    return info;
     
    5964    static NeverDestroyed<Vector<CaptureDevice>> info;
    6065    if (!info.get().size()) {
    61         info.get().append(CaptureDevice("239c24b2-2b15-11e3-8224-0800200c9a66", CaptureDevice::DeviceType::Video, "Mock video device 1"));
    62         info.get().append(CaptureDevice("239c24b3-2b15-11e3-8224-0800200c9a66", CaptureDevice::DeviceType::Video, "Mock video device 2"));
     66        auto captureDevice = CaptureDevice("239c24b2-2b15-11e3-8224-0800200c9a66", CaptureDevice::DeviceType::Video, "Mock video device 1");
     67        captureDevice.setEnabled(true);
     68        info.get().append(captureDevice);
     69
     70        captureDevice = CaptureDevice("239c24b3-2b15-11e3-8224-0800200c9a66", CaptureDevice::DeviceType::Video, "Mock video device 2");
     71        captureDevice.setEnabled(true);
     72        info.get().append(captureDevice);
    6373    }
    6474    return info;
  • trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp

    r215922 r215929  
    133133
    134134    if (!audioDeviceID.isEmpty()) {
    135         auto& audioDevices = MockRealtimeMediaSource::audioDevices();
    136         if (audioDeviceID == audioDevices[0].persistentId()) {
    137             auto source = MockRealtimeAudioSource::create(audioDevices[0].label(), audioConstraints);
    138             if (source)
    139                 audioSources.append(source.releaseNonNull());
    140         } else if (audioDeviceID == audioDevices[1].persistentId()) {
    141             auto source = MockRealtimeAudioSource::create(audioDevices[1].label(), audioConstraints);
    142             if (source)
    143                 audioSources.append(source.releaseNonNull());
     135        for (auto& captureDevice : MockRealtimeMediaSource::audioDevices()) {
     136            if (!captureDevice.enabled())
     137                continue;
     138
     139            if (audioDeviceID == captureDevice.persistentId()) {
     140                auto source = MockRealtimeAudioSource::create(captureDevice.label(), audioConstraints);
     141                if (source)
     142                    audioSources.append(source.releaseNonNull());
     143            }
    144144        }
    145145    }
    146146
    147147    if (!videoDeviceID.isEmpty()) {
    148         auto& videoDevices = MockRealtimeMediaSource::videoDevices();
    149         if (videoDeviceID == videoDevices[0].persistentId()) {
    150             auto source = MockRealtimeVideoSource::create(videoDevices[0].label(), videoConstraints);
    151             if (source)
    152                 videoSources.append(source.releaseNonNull());
    153         } else if (videoDeviceID == videoDevices[1].persistentId()) {
    154             auto source = MockRealtimeVideoSource::create(videoDevices[1].label(), videoConstraints);
    155             if (source)
    156                 videoSources.append(source.releaseNonNull());
     148        for (auto& captureDevice : MockRealtimeMediaSource::videoDevices()) {
     149            if (!captureDevice.enabled())
     150                continue;
     151
     152            if (videoDeviceID == captureDevice.persistentId()) {
     153                auto source = MockRealtimeVideoSource::create(captureDevice.label(), videoConstraints);
     154                if (source)
     155                    videoSources.append(source.releaseNonNull());
     156            }
    157157        }
    158158    }
     
    168168    Vector<CaptureDevice> sources;
    169169
    170     sources.appendVector(MockRealtimeMediaSource::audioDevices());
    171     sources.appendVector(MockRealtimeMediaSource::videoDevices());
     170    for (auto& captureDevice : MockRealtimeMediaSource::audioDevices()) {
     171        if (!captureDevice.enabled())
     172            continue;
     173
     174        sources.append(captureDevice);
     175    }
     176
     177    for (auto& captureDevice : MockRealtimeMediaSource::videoDevices()) {
     178        if (!captureDevice.enabled())
     179            continue;
     180
     181        sources.append(captureDevice);
     182    }
    172183
    173184    return sources;
     
    184195}
    185196
     197ExceptionOr<void> MockRealtimeMediaSourceCenter::setDeviceEnabled(const String& id, bool enabled)
     198{
     199    for (auto& captureDevice : getMediaStreamDevices()) {
     200        if (id == captureDevice.persistentId()) {
     201            if (enabled != captureDevice.enabled()) {
     202                captureDevice.setEnabled(enabled);
     203                captureDevicesChanged();
     204            }
     205
     206            return { };
     207        }
     208    }
     209
     210    return Exception { NOT_FOUND_ERR };
     211}
    186212
    187213} // namespace WebCore
  • trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h

    r213941 r215929  
    4848    RealtimeMediaSource::CaptureFactory* defaultAudioFactory() final;
    4949    RealtimeMediaSource::CaptureFactory* defaultVideoFactory() final;
     50
     51    ExceptionOr<void> setDeviceEnabled(const String& persistentID, bool) final;
    5052};
    5153
  • trunk/Source/WebCore/testing/Internals.cpp

    r215558 r215929  
    40264026}
    40274027
     4028ExceptionOr<void> Internals::setMediaDeviceState(const String& id, const String& property, bool value)
     4029{
     4030    auto* document = contextDocument();
     4031    if (!document)
     4032        return Exception { INVALID_ACCESS_ERR, ASCIILiteral("No context document") };
     4033
     4034    if (!equalLettersIgnoringASCIICase(property, "enabled"))
     4035        return Exception { INVALID_ACCESS_ERR, makeString("\"" + property, "\" is not a valid property for this method.") };
     4036
     4037    auto salt = document->deviceIDHashSalt();
     4038    std::optional<CaptureDevice> device = RealtimeMediaSourceCenter::singleton().captureDeviceWithUniqueID(id, salt);
     4039    if (!device)
     4040        return Exception { INVALID_ACCESS_ERR, makeString("device with ID \"" + id, "\" not found.") };
     4041
     4042    auto result = RealtimeMediaSourceCenter::singleton().setDeviceEnabled(device->persistentId(), value);
     4043    if (result.hasException())
     4044        return result.releaseException();
     4045
     4046    return { };
     4047}
     4048
    40284049#endif
    40294050
  • trunk/Source/WebCore/testing/Internals.h

    r215558 r215929  
    571571
    572572#if ENABLE(MEDIA_STREAM)
     573    ExceptionOr<void> setMediaDeviceState(const String& id, const String& property, bool value);
    573574    unsigned long trackAudioSampleCount() const { return m_trackAudioSampleCount; }
    574575    unsigned long trackVideoSampleCount() const { return m_trackVideoSampleCount; }
  • trunk/Source/WebCore/testing/Internals.idl

    r215558 r215929  
    537537    [Conditional=MEDIA_STREAM] readonly attribute unsigned long trackAudioSampleCount;
    538538    [Conditional=MEDIA_STREAM] readonly attribute unsigned long trackVideoSampleCount;
    539 };
     539    [Conditional=MEDIA_STREAM, MayThrowException] void setMediaDeviceState(DOMString deviceID, DOMString property, boolean value);
     540};
Note: See TracChangeset for help on using the changeset viewer.