Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / platform / mediastream / RealtimeMediaSourceCenter.cpp
1 /*
2  * Copyright (C) 2011 Ericsson AB. All rights reserved.
3  * Copyright (C) 2012 Google Inc. All rights reserved.
4  * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
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  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer
14  *    in the documentation and/or other materials provided with the
15  *    distribution.
16  * 3. Neither the name of Ericsson nor the names of its contributors
17  *    may be used to endorse or promote products derived from this
18  *    software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "config.h"
34 #include "RealtimeMediaSourceCenter.h"
35
36 #if ENABLE(MEDIA_STREAM)
37
38 // FIXME: GTK to implement its own RealtimeMediaSourceCenter.
39 #if PLATFORM(GTK)
40 #include "MockRealtimeMediaSourceCenter.h"
41 #endif
42
43 #include "CaptureDeviceManager.h"
44 #include "Logging.h"
45 #include "MediaStreamPrivate.h"
46 #include <wtf/SHA1.h>
47
48 namespace WebCore {
49
50 static RealtimeMediaSourceCenter*& mediaStreamCenterOverride()
51 {
52     static RealtimeMediaSourceCenter* override;
53     return override;
54 }
55
56 static HashMap<unsigned, std::function<void()>>& observerMap()
57 {
58     static NeverDestroyed<HashMap<unsigned, std::function<void()>>> map;
59     return map;
60 }
61
62 RealtimeMediaSourceCenter& RealtimeMediaSourceCenter::singleton()
63 {
64     RealtimeMediaSourceCenter* override = mediaStreamCenterOverride();
65     if (override)
66         return *override;
67 #if PLATFORM(GTK)
68     WTFLogAlways("WebKitGTK LIBWEBRTC RealtimeMediaSourceCenter NOT IMPLEMENTED. Returning MockRealtimeMediaSourceCenter instead to avoid crash!\n");
69     ASSERT(isMainThread());
70     static NeverDestroyed<MockRealtimeMediaSourceCenter> center;
71     return center;
72 #else
73     return RealtimeMediaSourceCenter::platformCenter();
74 #endif
75 }
76
77 void RealtimeMediaSourceCenter::setSharedStreamCenterOverride(RealtimeMediaSourceCenter* center)
78 {
79     mediaStreamCenterOverride() = center;
80 }
81
82 RealtimeMediaSourceCenter::RealtimeMediaSourceCenter()
83 {
84     m_supportedConstraints.setSupportsWidth(true);
85     m_supportedConstraints.setSupportsHeight(true);
86     m_supportedConstraints.setSupportsAspectRatio(true);
87     m_supportedConstraints.setSupportsFrameRate(true);
88     m_supportedConstraints.setSupportsFacingMode(true);
89     m_supportedConstraints.setSupportsVolume(true);
90     m_supportedConstraints.setSupportsDeviceId(true);
91 }
92
93 RealtimeMediaSourceCenter::~RealtimeMediaSourceCenter() = default;
94
95 void RealtimeMediaSourceCenter::createMediaStream(NewMediaStreamHandler&& completionHandler, const String& audioDeviceID, const String& videoDeviceID, const MediaConstraints* audioConstraints, const MediaConstraints* videoConstraints)
96 {
97     Vector<Ref<RealtimeMediaSource>> audioSources;
98     Vector<Ref<RealtimeMediaSource>> videoSources;
99     String invalidConstraint;
100
101     if (!audioDeviceID.isEmpty()) {
102         auto audioSource = audioFactory().createAudioCaptureSource(audioDeviceID, audioConstraints);
103         if (audioSource)
104             audioSources.append(audioSource.source());
105         else {
106 #if !LOG_DISABLED
107             if (!audioSource.errorMessage.isEmpty())
108                 LOG(Media, "RealtimeMediaSourceCenter::createMediaStream(%p), audio constraints failed to apply: %s", this, audioSource.errorMessage.utf8().data());
109 #endif
110             completionHandler(nullptr);
111             return;
112         }
113     }
114     if (!videoDeviceID.isEmpty()) {
115         auto videoSource = videoFactory().createVideoCaptureSource(videoDeviceID, videoConstraints);
116         if (videoSource)
117             videoSources.append(videoSource.source());
118         else {
119 #if !LOG_DISABLED
120             if (!videoSource.errorMessage.isEmpty())
121                 LOG(Media, "RealtimeMediaSourceCenter::createMediaStream(%p), video constraints failed to apply: %s", this, videoSource.errorMessage.utf8().data());
122 #endif
123             completionHandler(nullptr);
124             return;
125         }
126     }
127
128     completionHandler(MediaStreamPrivate::create(audioSources, videoSources));
129 }
130
131 Vector<CaptureDevice> RealtimeMediaSourceCenter::getMediaStreamDevices()
132 {
133     Vector<CaptureDevice> result;
134
135     result.appendVector(audioCaptureDeviceManager().getAudioSourcesInfo());
136     result.appendVector(videoCaptureDeviceManager().getVideoSourcesInfo());
137
138     return result;
139 }
140
141 void RealtimeMediaSourceCenter::setAudioFactory(RealtimeMediaSource::AudioCaptureFactory& factory)
142 {
143     m_audioFactory = &factory;
144 }
145
146 void RealtimeMediaSourceCenter::unsetAudioFactory(RealtimeMediaSource::AudioCaptureFactory& factory)
147 {
148     if (m_audioFactory == &factory)
149         m_audioFactory = nullptr;
150 }
151
152 RealtimeMediaSource::AudioCaptureFactory& RealtimeMediaSourceCenter::audioFactory()
153 {
154     return m_audioFactory ? *m_audioFactory : defaultAudioFactory();
155 }
156
157 void RealtimeMediaSourceCenter::setVideoFactory(RealtimeMediaSource::VideoCaptureFactory& factory)
158 {
159     m_videoFactory = &factory;
160 }
161
162 void RealtimeMediaSourceCenter::unsetVideoFactory(RealtimeMediaSource::VideoCaptureFactory& factory)
163 {
164     if (m_videoFactory == &factory)
165         m_videoFactory = nullptr;
166 }
167
168 RealtimeMediaSource::VideoCaptureFactory& RealtimeMediaSourceCenter::videoFactory()
169 {
170     return m_videoFactory ? *m_videoFactory : defaultVideoFactory();
171 }
172
173 void RealtimeMediaSourceCenter::setAudioCaptureDeviceManager(CaptureDeviceManager& deviceManager)
174 {
175     m_audioCaptureDeviceManager = &deviceManager;
176 }
177
178 void RealtimeMediaSourceCenter::unsetAudioCaptureDeviceManager(CaptureDeviceManager& deviceManager)
179 {
180     if (m_audioCaptureDeviceManager == &deviceManager)
181         m_audioCaptureDeviceManager = nullptr;
182 }
183
184 CaptureDeviceManager& RealtimeMediaSourceCenter::audioCaptureDeviceManager()
185 {
186     return m_audioCaptureDeviceManager ? *m_audioCaptureDeviceManager : defaultAudioCaptureDeviceManager();
187 }
188
189 void RealtimeMediaSourceCenter::setVideoCaptureDeviceManager(CaptureDeviceManager& deviceManager)
190 {
191     m_videoCaptureDeviceManager = &deviceManager;
192 }
193
194 void RealtimeMediaSourceCenter::unsetVideoCaptureDeviceManager(CaptureDeviceManager& deviceManager)
195 {
196     if (m_videoCaptureDeviceManager == &deviceManager)
197         m_videoCaptureDeviceManager = nullptr;
198 }
199
200 CaptureDeviceManager& RealtimeMediaSourceCenter::videoCaptureDeviceManager()
201 {
202     return m_videoCaptureDeviceManager ? *m_videoCaptureDeviceManager : defaultVideoCaptureDeviceManager();
203 }
204
205 static void addStringToSHA1(SHA1& sha1, const String& string)
206 {
207     if (string.isEmpty())
208         return;
209
210     if (string.is8Bit() && string.containsOnlyASCII()) {
211         const uint8_t nullByte = 0;
212         sha1.addBytes(string.characters8(), string.length());
213         sha1.addBytes(&nullByte, 1);
214         return;
215     }
216
217     auto utf8 = string.utf8();
218     sha1.addBytes(reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length() + 1); // Include terminating null byte.
219 }
220
221 String RealtimeMediaSourceCenter::hashStringWithSalt(const String& id, const String& hashSalt)
222 {
223     if (id.isEmpty() || hashSalt.isEmpty())
224         return emptyString();
225
226     SHA1 sha1;
227
228     addStringToSHA1(sha1, id);
229     addStringToSHA1(sha1, hashSalt);
230     
231     SHA1::Digest digest;
232     sha1.computeHash(digest);
233     
234     return SHA1::hexDigest(digest).data();
235 }
236
237 std::optional<CaptureDevice> RealtimeMediaSourceCenter::captureDeviceWithUniqueID(const String& uniqueID, const String& idHashSalt)
238 {
239     for (auto& device : getMediaStreamDevices()) {
240         if (uniqueID == hashStringWithSalt(device.persistentId(), idHashSalt))
241             return device;
242     }
243
244     return std::nullopt;
245 }
246
247 ExceptionOr<void> RealtimeMediaSourceCenter::setDeviceEnabled(const String& id, bool enabled)
248 {
249     for (auto& captureDevice : getMediaStreamDevices()) {
250         if (id == captureDevice.persistentId()) {
251             if (enabled != captureDevice.enabled()) {
252                 captureDevice.setEnabled(enabled);
253                 captureDevicesChanged();
254             }
255
256             return { };
257         }
258     }
259
260     return Exception { NotFoundError };
261 }
262
263 RealtimeMediaSourceCenter::DevicesChangedObserverToken RealtimeMediaSourceCenter::addDevicesChangedObserver(std::function<void()>&& observer)
264 {
265     static DevicesChangedObserverToken nextToken = 0;
266     observerMap().set(++nextToken, WTFMove(observer));
267     return nextToken;
268 }
269
270 void RealtimeMediaSourceCenter::removeDevicesChangedObserver(DevicesChangedObserverToken token)
271 {
272     bool wasRemoved = observerMap().remove(token);
273     ASSERT_UNUSED(wasRemoved, wasRemoved);
274 }
275
276 void RealtimeMediaSourceCenter::captureDevicesChanged()
277 {
278     // Copy the hash map because the observer callback may call back in and modify the map.
279     auto callbacks = observerMap();
280     for (auto& it : callbacks)
281         it.value();
282 }
283
284 void RealtimeMediaSourceCenter::validateRequestConstraints(ValidConstraintsHandler&& validHandler, InvalidConstraintsHandler&& invalidHandler, const MediaConstraints& audioConstraints, const MediaConstraints& videoConstraints, String&& deviceIdentifierHashSalt)
285 {
286     struct DeviceInfo {
287         unsigned fitnessScore;
288         String id;
289     };
290
291     struct {
292         bool operator()(const DeviceInfo& a, const DeviceInfo& b)
293         {
294             return a.fitnessScore < b.fitnessScore;
295         }
296     } sortBasedOnFitnessScore;
297
298     Vector<DeviceInfo> audioDeviceInfo;
299     Vector<DeviceInfo> videoDeviceInfo;
300
301     String firstInvalidConstraint;
302     for (auto& device : getMediaStreamDevices()) {
303         if (!device.enabled())
304             continue;
305
306         String invalidConstraint;
307         CaptureSourceOrError sourceOrError;
308         if (device.type() == CaptureDevice::DeviceType::Video && videoConstraints.isValid) {
309             auto sourceOrError = videoFactory().createVideoCaptureSource(device.persistentId(), nullptr);
310             if (sourceOrError && sourceOrError.captureSource->supportsConstraints(videoConstraints, invalidConstraint))
311                 videoDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device.persistentId()});
312         } else if (device.type() == CaptureDevice::DeviceType::Audio && audioConstraints.isValid) {
313             auto sourceOrError = audioFactory().createAudioCaptureSource(device.persistentId(), nullptr);
314             if (sourceOrError && sourceOrError.captureSource->supportsConstraints(audioConstraints, invalidConstraint))
315                 audioDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device.persistentId()});
316         }
317
318         if (!invalidConstraint.isEmpty() && firstInvalidConstraint.isEmpty())
319             firstInvalidConstraint = invalidConstraint;
320     }
321
322     if ((audioConstraints.isValid && audioDeviceInfo.isEmpty()) || (videoConstraints.isValid && videoDeviceInfo.isEmpty())) {
323         invalidHandler(firstInvalidConstraint);
324         return;
325     }
326
327     Vector<String> audioSourceIds;
328     if (!audioDeviceInfo.isEmpty()) {
329         audioSourceIds.reserveInitialCapacity(audioDeviceInfo.size());
330         std::sort(audioDeviceInfo.begin(), audioDeviceInfo.end(), sortBasedOnFitnessScore);
331         for (auto& info : audioDeviceInfo)
332             audioSourceIds.uncheckedAppend(WTFMove(info.id));
333     }
334
335     Vector<String> videoSourceIds;
336     if (!videoDeviceInfo.isEmpty()) {
337         videoSourceIds.reserveInitialCapacity(videoDeviceInfo.size());
338         std::sort(videoDeviceInfo.begin(), videoDeviceInfo.end(), sortBasedOnFitnessScore);
339         for (auto& info : videoDeviceInfo)
340             videoSourceIds.uncheckedAppend(WTFMove(info.id));
341     }
342
343     validHandler(WTFMove(audioSourceIds), WTFMove(videoSourceIds), WTFMove(deviceIdentifierHashSalt));
344 }
345
346 void RealtimeMediaSourceCenter::setVideoCapturePageState(bool interrupted, bool pageMuted)
347 {
348     videoFactory().setVideoCapturePageState(interrupted, pageMuted);
349 }
350
351 } // namespace WebCore
352
353 #endif // ENABLE(MEDIA_STREAM)