Support arbitrary video resolution in getUserMedia API
[WebKit-https.git] / Source / WebCore / platform / mock / MockRealtimeMediaSourceCenter.cpp
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  * Copyright (C) 2013-2018 Apple Inc.  All rights reserved.
4  * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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 in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29 #include "MockRealtimeMediaSourceCenter.h"
30
31 #if ENABLE(MEDIA_STREAM)
32
33 #include "CaptureDevice.h"
34 #include "Logging.h"
35 #include "MediaConstraints.h"
36 #include "MockRealtimeAudioSource.h"
37 #include "MockRealtimeVideoSource.h"
38 #include "NotImplemented.h"
39 #include "RealtimeMediaSourceSettings.h"
40 #include <math.h>
41 #include <wtf/NeverDestroyed.h>
42 #include <wtf/text/StringView.h>
43
44 namespace WebCore {
45
46 static inline Vector<MockMediaDevice> defaultDevices()
47 {
48     return Vector<MockMediaDevice> {
49         MockMediaDevice { "239c24b0-2b15-11e3-8224-0800200c9a66"_s, "Mock audio device 1"_s, MockMicrophoneProperties { 44100 } },
50         MockMediaDevice { "239c24b1-2b15-11e3-8224-0800200c9a66"_s, "Mock audio device 2"_s, MockMicrophoneProperties { 48000 } },
51
52         MockMediaDevice { "239c24b2-2b15-11e3-8224-0800200c9a66"_s, "Mock video device 1"_s,
53             MockCameraProperties {
54                 30,
55                 RealtimeMediaSourceSettings::VideoFacingMode::User, {
56                     { { 1280, 720 }, { { 30, 30}, { 27.5, 27.5}, { 25, 25}, { 22.5, 22.5}, { 20, 20}, { 17.5, 17.5}, { 15, 15}, { 12.5, 12.5}, { 10, 10}, { 7.5, 7.5}, { 5, 5} } },
57                     { { 640, 480 },  { { 30, 30}, { 27.5, 27.5}, { 25, 25}, { 22.5, 22.5}, { 20, 20}, { 17.5, 17.5}, { 15, 15}, { 12.5, 12.5}, { 10, 10}, { 7.5, 7.5}, { 5, 5} } },
58                 },
59                 Color::black,
60             } },
61
62         MockMediaDevice { "239c24b3-2b15-11e3-8224-0800200c9a66"_s, "Mock video device 2"_s,
63             MockCameraProperties {
64                 15,
65                 RealtimeMediaSourceSettings::VideoFacingMode::Environment, {
66                     { { 3840, 2160 }, { { 2, 30 } } },
67                     { { 1920, 1080 }, { { 2, 30 } } },
68                     { { 1280, 720 },  { { 3, 120 } } },
69                     { { 960, 540 },   { { 3, 60 } } },
70                     { { 640, 480 },   { { 2, 30 } } },
71                     { { 352, 288 },   { { 2, 30 } } },
72                     { { 320, 240 },   { { 2, 30 } } },
73                     { { 160, 120 },   { { 2, 30 } } },
74                 },
75                 Color::darkGray,
76             } },
77
78         MockMediaDevice { "SCREEN-1"_s, "Mock screen device 1"_s, MockDisplayProperties { 30, Color::lightGray } },
79         MockMediaDevice { "SCREEN-2"_s, "Mock screen device 2"_s, MockDisplayProperties { 10, Color::yellow } }
80     };
81 }
82
83 static Vector<MockMediaDevice>& devices()
84 {
85     static auto devices = makeNeverDestroyed([] {
86         return defaultDevices();
87     }());
88     return devices;
89 }
90
91 static HashMap<String, MockMediaDevice>& deviceMap()
92 {
93     static auto map = makeNeverDestroyed([] {
94         HashMap<String, MockMediaDevice> map;
95         for (auto& device : devices())
96             map.add(device.persistentId, device);
97
98         return map;
99     }());
100     return map;
101 }
102
103 static inline Vector<CaptureDevice>& deviceListForDevice(const MockMediaDevice& device)
104 {
105     if (device.isMicrophone())
106         return MockRealtimeMediaSourceCenter::audioDevices();
107     if (device.isCamera())
108         return MockRealtimeMediaSourceCenter::videoDevices();
109
110     ASSERT(device.isDisplay());
111     return MockRealtimeMediaSourceCenter::displayDevices();
112 }
113
114 MockRealtimeMediaSourceCenter& MockRealtimeMediaSourceCenter::singleton()
115 {
116     static NeverDestroyed<MockRealtimeMediaSourceCenter> center;
117     return center;
118 }
119
120 void MockRealtimeMediaSourceCenter::setMockRealtimeMediaSourceCenterEnabled(bool enabled)
121 {
122     static bool active = false;
123     if (active != enabled) {
124         active = enabled;
125         RealtimeMediaSourceCenter::setSharedStreamCenterOverride(enabled ? &singleton() : nullptr);
126     }
127 }
128
129 static void createCaptureDevice(const MockMediaDevice& device)
130 {
131     deviceListForDevice(device).append(MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(device.type(), device.persistentId).value());
132 }
133
134 void MockRealtimeMediaSourceCenter::resetDevices()
135 {
136     setDevices(defaultDevices());
137     RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
138 }
139
140 void MockRealtimeMediaSourceCenter::setDevices(Vector<MockMediaDevice>&& newMockDevices)
141 {
142     audioDevices().clear();
143     videoDevices().clear();
144     displayDevices().clear();
145
146     auto& mockDevices = devices();
147     mockDevices = WTFMove(newMockDevices);
148
149     auto& map = deviceMap();
150     map.clear();
151
152     for (const auto& device : mockDevices) {
153         map.add(device.persistentId, device);
154         createCaptureDevice(device);
155     }
156     RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
157 }
158
159 void MockRealtimeMediaSourceCenter::addDevice(const MockMediaDevice& device)
160 {
161     devices().append(device);
162     deviceMap().set(device.persistentId, device);
163     createCaptureDevice(device);
164     RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
165 }
166
167 void MockRealtimeMediaSourceCenter::removeDevice(const String& persistentId)
168 {
169     auto& map = deviceMap();
170     auto iterator = map.find(persistentId);
171     if (iterator == map.end())
172         return;
173
174     devices().removeFirstMatching([&persistentId](const auto& device) {
175         return device.persistentId == persistentId;
176     });
177
178     deviceListForDevice(iterator->value).removeFirstMatching([&persistentId](const auto& device) {
179         return device.persistentId() == persistentId;
180     });
181
182     map.remove(iterator);
183     RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
184 }
185
186 std::optional<MockMediaDevice> MockRealtimeMediaSourceCenter::mockDeviceWithPersistentID(const String& id)
187 {
188     ASSERT(!id.isEmpty());
189
190     auto& map = deviceMap();
191     auto iterator = map.find(id);
192     if (iterator == map.end())
193         return std::nullopt;
194
195     return iterator->value;
196 }
197
198 std::optional<CaptureDevice> MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id)
199 {
200     ASSERT(!id.isEmpty());
201
202     auto& map = deviceMap();
203     auto iterator = map.find(id);
204     if (iterator == map.end() || iterator->value.type() != type)
205         return std::nullopt;
206
207     CaptureDevice device { iterator->value.persistentId, type, iterator->value.label };
208     device.setEnabled(true);
209     return WTFMove(device);
210 }
211
212 Vector<CaptureDevice>& MockRealtimeMediaSourceCenter::audioDevices()
213 {
214     static auto audioDevices = makeNeverDestroyed([] {
215         Vector<CaptureDevice> audioDevices;
216         for (const auto& device : devices()) {
217             if (device.type() == CaptureDevice::DeviceType::Microphone)
218                 audioDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Microphone, device.persistentId).value());
219         }
220         return audioDevices;
221     }());
222
223     return audioDevices;
224 }
225
226 Vector<CaptureDevice>& MockRealtimeMediaSourceCenter::videoDevices()
227 {
228     static auto videoDevices = makeNeverDestroyed([] {
229         Vector<CaptureDevice> videoDevices;
230         for (const auto& device : devices()) {
231             if (device.type() == CaptureDevice::DeviceType::Camera)
232                 videoDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Camera, device.persistentId).value());
233         }
234         return videoDevices;
235     }());
236
237     return videoDevices;
238 }
239
240 Vector<CaptureDevice>& MockRealtimeMediaSourceCenter::displayDevices()
241 {
242     static auto displayDevices = makeNeverDestroyed([] {
243         Vector<CaptureDevice> displayDevices;
244         for (const auto& device : devices()) {
245             if (device.type() == CaptureDevice::DeviceType::Screen)
246                 displayDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Screen, device.persistentId).value());
247         }
248         return displayDevices;
249     }());
250
251     return displayDevices;
252 }
253
254 } // namespace WebCore
255
256 #endif // ENABLE(MEDIA_STREAM)