[MediaStream] RealtimeMediaSource should be able to vend hashed IDs
[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 { CaptureDevice::DeviceType::Screen, Color::lightGray, { 3840, 2160 } } },
79         MockMediaDevice { "SCREEN-2"_s, "Mock screen device 2"_s, MockDisplayProperties { CaptureDevice::DeviceType::Screen, Color::yellow, { 1920, 1080 } } },
80
81         MockMediaDevice { "WINDOW-2"_s, "Mock window 1"_s, MockDisplayProperties { CaptureDevice::DeviceType::Screen, 0xfff1b5, { 640, 480 } } },
82         MockMediaDevice { "WINDOW-2"_s, "Mock window 2"_s, MockDisplayProperties { CaptureDevice::DeviceType::Screen, 0xffd0b5, { 1280, 600 } } },
83     };
84 }
85
86 class MockRealtimeVideoSourceFactory : public VideoCaptureFactory {
87 public:
88     CaptureSourceOrError createVideoCaptureSource(const CaptureDevice& device, String&& hashSalt, const MediaConstraints* constraints) final
89     {
90         ASSERT(device.type() == CaptureDevice::DeviceType::Camera);
91         ASSERT(MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(CaptureDevice::DeviceType::Camera, device.persistentId()));
92
93         return MockRealtimeVideoSource::create(String { device.persistentId() }, String { device.label() }, WTFMove(hashSalt), constraints);
94     }
95
96 #if PLATFORM(IOS)
97 private:
98     void setVideoCapturePageState(bool interrupted, bool pageMuted)
99     {
100         if (activeSource())
101             activeSource()->setInterrupted(interrupted, pageMuted);
102     }
103 #endif
104 };
105
106 class MockRealtimeDisplaySourceFactory : public DisplayCaptureFactory {
107 public:
108     CaptureSourceOrError createDisplayCaptureSource(const CaptureDevice& device, const MediaConstraints* constraints) final
109     {
110         ASSERT(MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(device.type(), device.persistentId()));
111
112         switch (device.type()) {
113         case CaptureDevice::DeviceType::Screen:
114         case CaptureDevice::DeviceType::Window:
115             return MockRealtimeVideoSource::create(String { device.persistentId() }, String { }, String { device.label() }, constraints);
116             break;
117         case CaptureDevice::DeviceType::Application:
118         case CaptureDevice::DeviceType::Browser:
119         case CaptureDevice::DeviceType::Microphone:
120         case CaptureDevice::DeviceType::Camera:
121         case CaptureDevice::DeviceType::Unknown:
122             ASSERT_NOT_REACHED();
123             break;
124         }
125
126         return { };
127     }
128 };
129
130 class MockRealtimeAudioSourceFactory : public AudioCaptureFactory {
131 public:
132     CaptureSourceOrError createAudioCaptureSource(const CaptureDevice& device, String&& hashSalt, const MediaConstraints* constraints) final
133     {
134         ASSERT(device.type() == CaptureDevice::DeviceType::Microphone);
135         ASSERT(MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(CaptureDevice::DeviceType::Microphone, device.persistentId()));
136
137         return MockRealtimeAudioSource::create(String { device.persistentId() }, String { device.label() }, WTFMove(hashSalt), constraints);
138     }
139 };
140
141 static Vector<MockMediaDevice>& devices()
142 {
143     static auto devices = makeNeverDestroyed([] {
144         return defaultDevices();
145     }());
146     return devices;
147 }
148
149 static HashMap<String, MockMediaDevice>& deviceMap()
150 {
151     static auto map = makeNeverDestroyed([] {
152         HashMap<String, MockMediaDevice> map;
153         for (auto& device : devices())
154             map.add(device.persistentId, device);
155
156         return map;
157     }());
158     return map;
159 }
160
161 static inline Vector<CaptureDevice>& deviceListForDevice(const MockMediaDevice& device)
162 {
163     if (device.isMicrophone())
164         return MockRealtimeMediaSourceCenter::audioDevices();
165     if (device.isCamera())
166         return MockRealtimeMediaSourceCenter::videoDevices();
167
168     ASSERT(device.isDisplay());
169     return MockRealtimeMediaSourceCenter::displayDevices();
170 }
171
172 MockRealtimeMediaSourceCenter& MockRealtimeMediaSourceCenter::singleton()
173 {
174     static NeverDestroyed<MockRealtimeMediaSourceCenter> center;
175     return center;
176 }
177
178 void MockRealtimeMediaSourceCenter::setMockRealtimeMediaSourceCenterEnabled(bool enabled)
179 {
180     static bool active = false;
181     if (active != enabled) {
182         active = enabled;
183         RealtimeMediaSourceCenter::setSharedStreamCenterOverride(enabled ? &singleton() : nullptr);
184     }
185 }
186
187 static void createCaptureDevice(const MockMediaDevice& device)
188 {
189     deviceListForDevice(device).append(MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(device.type(), device.persistentId).value());
190 }
191
192 void MockRealtimeMediaSourceCenter::resetDevices()
193 {
194     setDevices(defaultDevices());
195     RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
196 }
197
198 void MockRealtimeMediaSourceCenter::setDevices(Vector<MockMediaDevice>&& newMockDevices)
199 {
200     audioDevices().clear();
201     videoDevices().clear();
202     displayDevices().clear();
203
204     auto& mockDevices = devices();
205     mockDevices = WTFMove(newMockDevices);
206
207     auto& map = deviceMap();
208     map.clear();
209
210     for (const auto& device : mockDevices) {
211         map.add(device.persistentId, device);
212         createCaptureDevice(device);
213     }
214     RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
215 }
216
217 void MockRealtimeMediaSourceCenter::addDevice(const MockMediaDevice& device)
218 {
219     devices().append(device);
220     deviceMap().set(device.persistentId, device);
221     createCaptureDevice(device);
222     RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
223 }
224
225 void MockRealtimeMediaSourceCenter::removeDevice(const String& persistentId)
226 {
227     auto& map = deviceMap();
228     auto iterator = map.find(persistentId);
229     if (iterator == map.end())
230         return;
231
232     devices().removeFirstMatching([&persistentId](const auto& device) {
233         return device.persistentId == persistentId;
234     });
235
236     deviceListForDevice(iterator->value).removeFirstMatching([&persistentId](const auto& device) {
237         return device.persistentId() == persistentId;
238     });
239
240     map.remove(iterator);
241     RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
242 }
243
244 std::optional<MockMediaDevice> MockRealtimeMediaSourceCenter::mockDeviceWithPersistentID(const String& id)
245 {
246     ASSERT(!id.isEmpty());
247
248     auto& map = deviceMap();
249     auto iterator = map.find(id);
250     if (iterator == map.end())
251         return std::nullopt;
252
253     return iterator->value;
254 }
255
256 std::optional<CaptureDevice> MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id)
257 {
258     ASSERT(!id.isEmpty());
259
260     auto& map = deviceMap();
261     auto iterator = map.find(id);
262     if (iterator == map.end() || iterator->value.type() != type)
263         return std::nullopt;
264
265     CaptureDevice device { iterator->value.persistentId, type, iterator->value.label };
266     device.setEnabled(true);
267     return WTFMove(device);
268 }
269
270 Vector<CaptureDevice>& MockRealtimeMediaSourceCenter::audioDevices()
271 {
272     static auto audioDevices = makeNeverDestroyed([] {
273         Vector<CaptureDevice> audioDevices;
274         for (const auto& device : devices()) {
275             if (device.isMicrophone())
276                 audioDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Microphone, device.persistentId).value());
277         }
278         return audioDevices;
279     }());
280
281     return audioDevices;
282 }
283
284 Vector<CaptureDevice>& MockRealtimeMediaSourceCenter::videoDevices()
285 {
286     static auto videoDevices = makeNeverDestroyed([] {
287         Vector<CaptureDevice> videoDevices;
288         for (const auto& device : devices()) {
289             if (device.isCamera())
290                 videoDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Camera, device.persistentId).value());
291         }
292         return videoDevices;
293     }());
294
295     return videoDevices;
296 }
297
298 Vector<CaptureDevice>& MockRealtimeMediaSourceCenter::displayDevices()
299 {
300     static auto displayDevices = makeNeverDestroyed([] {
301         Vector<CaptureDevice> displayDevices;
302         for (const auto& device : devices()) {
303             if (device.isDisplay())
304                 displayDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Screen, device.persistentId).value());
305         }
306         return displayDevices;
307     }());
308
309     return displayDevices;
310 }
311
312 AudioCaptureFactory& MockRealtimeMediaSourceCenter::audioFactory()
313 {
314     static NeverDestroyed<MockRealtimeAudioSourceFactory> factory;
315     return factory.get();
316 }
317
318 VideoCaptureFactory& MockRealtimeMediaSourceCenter::videoFactory()
319 {
320     static NeverDestroyed<MockRealtimeVideoSourceFactory> factory;
321     return factory.get();
322 }
323
324 DisplayCaptureFactory& MockRealtimeMediaSourceCenter::displayCaptureFactory()
325 {
326     static NeverDestroyed<MockRealtimeDisplaySourceFactory> factory;
327     return factory.get();
328 }
329
330 } // namespace WebCore
331
332 #endif // ENABLE(MEDIA_STREAM)