WeakPtrFactory should populate m_ref lazily.
[WebKit-https.git] / Source / WebCore / Modules / mediastream / MediaDevices.cpp
1 /*
2  * Copyright (C) 2015 Ericsson AB. All rights reserved.
3  * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer
13  *    in the documentation and/or other materials provided with the
14  *    distribution.
15  * 3. Neither the name of Ericsson nor the names of its contributors
16  *    may be used to endorse or promote products derived from this
17  *    software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "MediaDevices.h"
34
35 #if ENABLE(MEDIA_STREAM)
36
37 #include "Document.h"
38 #include "Event.h"
39 #include "EventNames.h"
40 #include "MediaDevicesRequest.h"
41 #include "MediaTrackSupportedConstraints.h"
42 #include "UserMediaRequest.h"
43 #include <wtf/RandomNumber.h>
44
45 namespace WebCore {
46
47 inline MediaDevices::MediaDevices(Document& document)
48     : ContextDestructionObserver(&document)
49     , m_scheduledEventTimer(*this, &MediaDevices::scheduledEventTimerFired)
50 {
51     m_deviceChangedToken = RealtimeMediaSourceCenter::singleton().addDevicesChangedObserver([weakThis = createWeakPtr(), this]() {
52
53         if (!weakThis)
54             return;
55
56         // FIXME: We should only dispatch an event if the user has been granted access to the type of
57         // device that was added or removed.
58         if (!m_scheduledEventTimer.isActive())
59             m_scheduledEventTimer.startOneShot(Seconds(randomNumber() / 2));
60     });
61 }
62
63 MediaDevices::~MediaDevices()
64 {
65     if (m_deviceChangedToken)
66         RealtimeMediaSourceCenter::singleton().removeDevicesChangedObserver(m_deviceChangedToken.value());
67 }
68
69 Ref<MediaDevices> MediaDevices::create(Document& document)
70 {
71     return adoptRef(*new MediaDevices(document));
72 }
73
74 Document* MediaDevices::document() const
75 {
76     return downcast<Document>(scriptExecutionContext());
77 }
78
79 static MediaConstraints createMediaConstraints(const Variant<bool, MediaTrackConstraints>& constraints)
80 {
81     return WTF::switchOn(constraints,
82         [&] (bool isValid) {
83             MediaConstraints constraints;
84             constraints.isValid = isValid;
85             return constraints;
86         },
87         [&] (const MediaTrackConstraints& trackConstraints) {
88             return createMediaConstraints(trackConstraints);
89         }
90     );
91 }
92
93 ExceptionOr<void> MediaDevices::getUserMedia(const StreamConstraints& constraints, Promise&& promise) const
94 {
95     auto* document = this->document();
96     if (!document)
97         return Exception { InvalidStateError };
98
99     auto audioConstraints = createMediaConstraints(constraints.audio);
100     auto videoConstraints = createMediaConstraints(constraints.video);
101     if (videoConstraints.isValid)
102         videoConstraints.setDefaultVideoConstraints();
103     return UserMediaRequest::start(*document, WTFMove(audioConstraints), WTFMove(videoConstraints), WTFMove(promise));
104 }
105
106 void MediaDevices::enumerateDevices(EnumerateDevicesPromise&& promise) const
107 {
108     auto* document = this->document();
109     if (!document)
110         return;
111     MediaDevicesRequest::create(*document, WTFMove(promise))->start();
112 }
113
114 MediaTrackSupportedConstraints MediaDevices::getSupportedConstraints()
115 {
116     auto& supported = RealtimeMediaSourceCenter::singleton().supportedConstraints();
117     MediaTrackSupportedConstraints result;
118     result.width = supported.supportsWidth();
119     result.height = supported.supportsHeight();
120     result.aspectRatio = supported.supportsAspectRatio();
121     result.frameRate = supported.supportsFrameRate();
122     result.facingMode = supported.supportsFacingMode();
123     result.volume = supported.supportsVolume();
124     result.sampleRate = supported.supportsSampleRate();
125     result.sampleSize = supported.supportsSampleSize();
126     result.echoCancellation = supported.supportsEchoCancellation();
127     result.deviceId = supported.supportsDeviceId();
128     result.groupId = supported.supportsGroupId();
129     return result;
130 }
131
132 void MediaDevices::scheduledEventTimerFired()
133 {
134     dispatchEvent(Event::create(eventNames().devicechangeEvent, false, false));
135 }
136
137 } // namespace WebCore
138
139 #endif // ENABLE(MEDIA_STREAM)