025c4ec3d157feb6c3e1ddd6f51d95b567f81b2f
[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 #include "CaptureDeviceManager.h"
39 #include "Logging.h"
40 #include "MediaStreamPrivate.h"
41 #include <wtf/SHA1.h>
42
43 namespace WebCore {
44
45 static RealtimeMediaSourceCenter*& mediaStreamCenterOverride()
46 {
47     static RealtimeMediaSourceCenter* override;
48     return override;
49 }
50
51 static HashMap<unsigned, std::function<void()>>& observerMap()
52 {
53     static NeverDestroyed<HashMap<unsigned, std::function<void()>>> map;
54     return map;
55 }
56
57 RealtimeMediaSourceCenter& RealtimeMediaSourceCenter::singleton()
58 {
59     RealtimeMediaSourceCenter* override = mediaStreamCenterOverride();
60     if (override)
61         return *override;
62     
63     return RealtimeMediaSourceCenter::platformCenter();
64 }
65
66 void RealtimeMediaSourceCenter::setSharedStreamCenterOverride(RealtimeMediaSourceCenter* center)
67 {
68     mediaStreamCenterOverride() = center;
69 }
70
71 RealtimeMediaSourceCenter::RealtimeMediaSourceCenter()
72 {
73     m_supportedConstraints.setSupportsWidth(true);
74     m_supportedConstraints.setSupportsHeight(true);
75     m_supportedConstraints.setSupportsAspectRatio(true);
76     m_supportedConstraints.setSupportsFrameRate(true);
77     m_supportedConstraints.setSupportsFacingMode(true);
78     m_supportedConstraints.setSupportsVolume(true);
79     m_supportedConstraints.setSupportsDeviceId(true);
80 }
81
82 RealtimeMediaSourceCenter::~RealtimeMediaSourceCenter()
83 {
84 }
85
86 void RealtimeMediaSourceCenter::createMediaStream(NewMediaStreamHandler&& completionHandler, const String& audioDeviceID, const String& videoDeviceID, const MediaConstraints* audioConstraints, const MediaConstraints* videoConstraints)
87 {
88     Vector<Ref<RealtimeMediaSource>> audioSources;
89     Vector<Ref<RealtimeMediaSource>> videoSources;
90     String invalidConstraint;
91
92     if (!audioDeviceID.isEmpty()) {
93         auto audioSource = audioFactory().createAudioCaptureSource(audioDeviceID, audioConstraints);
94         if (audioSource)
95             audioSources.append(audioSource.source());
96         else {
97 #if !LOG_DISABLED
98             if (!audioSource.errorMessage.isEmpty())
99                 LOG(Media, "RealtimeMediaSourceCenter::createMediaStream(%p), audio constraints failed to apply: %s", this, audioSource.errorMessage.utf8().data());
100 #endif
101             completionHandler(nullptr);
102             return;
103         }
104     }
105     if (!videoDeviceID.isEmpty()) {
106         auto videoSource = videoFactory().createVideoCaptureSource(videoDeviceID, videoConstraints);
107         if (videoSource)
108             videoSources.append(videoSource.source());
109         else {
110 #if !LOG_DISABLED
111             if (!videoSource.errorMessage.isEmpty())
112                 LOG(Media, "RealtimeMediaSourceCenter::createMediaStream(%p), video constraints failed to apply: %s", this, videoSource.errorMessage.utf8().data());
113 #endif
114             completionHandler(nullptr);
115             return;
116         }
117     }
118
119     completionHandler(MediaStreamPrivate::create(audioSources, videoSources));
120 }
121
122 Vector<CaptureDevice> RealtimeMediaSourceCenter::getMediaStreamDevices()
123 {
124     Vector<CaptureDevice> result;
125
126     result.appendVector(audioCaptureDeviceManager().getAudioSourcesInfo());
127     result.appendVector(videoCaptureDeviceManager().getVideoSourcesInfo());
128
129     return result;
130 }
131
132 void RealtimeMediaSourceCenter::setAudioFactory(RealtimeMediaSource::AudioCaptureFactory& factory)
133 {
134     m_audioFactory = &factory;
135 }
136
137 void RealtimeMediaSourceCenter::unsetAudioFactory(RealtimeMediaSource::AudioCaptureFactory& factory)
138 {
139     if (m_audioFactory == &factory)
140         m_audioFactory = nullptr;
141 }
142
143 RealtimeMediaSource::AudioCaptureFactory& RealtimeMediaSourceCenter::audioFactory()
144 {
145     return m_audioFactory ? *m_audioFactory : defaultAudioFactory();
146 }
147
148 void RealtimeMediaSourceCenter::setVideoFactory(RealtimeMediaSource::VideoCaptureFactory& factory)
149 {
150     m_videoFactory = &factory;
151 }
152
153 void RealtimeMediaSourceCenter::unsetVideoFactory(RealtimeMediaSource::VideoCaptureFactory& factory)
154 {
155     if (m_videoFactory == &factory)
156         m_videoFactory = nullptr;
157 }
158
159 RealtimeMediaSource::VideoCaptureFactory& RealtimeMediaSourceCenter::videoFactory()
160 {
161     return m_videoFactory ? *m_videoFactory : defaultVideoFactory();
162 }
163
164 void RealtimeMediaSourceCenter::setAudioCaptureDeviceManager(CaptureDeviceManager& deviceManager)
165 {
166     m_audioCaptureDeviceManager = &deviceManager;
167 }
168
169 void RealtimeMediaSourceCenter::unsetAudioCaptureDeviceManager(CaptureDeviceManager& deviceManager)
170 {
171     if (m_audioCaptureDeviceManager == &deviceManager)
172         m_audioCaptureDeviceManager = nullptr;
173 }
174
175 CaptureDeviceManager& RealtimeMediaSourceCenter::audioCaptureDeviceManager()
176 {
177     return m_audioCaptureDeviceManager ? *m_audioCaptureDeviceManager : defaultAudioCaptureDeviceManager();
178 }
179
180 void RealtimeMediaSourceCenter::setVideoCaptureDeviceManager(CaptureDeviceManager& deviceManager)
181 {
182     m_videoCaptureDeviceManager = &deviceManager;
183 }
184
185 void RealtimeMediaSourceCenter::unsetVideoCaptureDeviceManager(CaptureDeviceManager& deviceManager)
186 {
187     if (m_videoCaptureDeviceManager == &deviceManager)
188         m_videoCaptureDeviceManager = nullptr;
189 }
190
191 CaptureDeviceManager& RealtimeMediaSourceCenter::videoCaptureDeviceManager()
192 {
193     return m_videoCaptureDeviceManager ? *m_videoCaptureDeviceManager : defaultVideoCaptureDeviceManager();
194 }
195
196 static void addStringToSHA1(SHA1& sha1, const String& string)
197 {
198     if (string.isEmpty())
199         return;
200
201     if (string.is8Bit() && string.containsOnlyASCII()) {
202         const uint8_t nullByte = 0;
203         sha1.addBytes(string.characters8(), string.length());
204         sha1.addBytes(&nullByte, 1);
205         return;
206     }
207
208     auto utf8 = string.utf8();
209     sha1.addBytes(reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length() + 1); // Include terminating null byte.
210 }
211
212 String RealtimeMediaSourceCenter::hashStringWithSalt(const String& id, const String& hashSalt)
213 {
214     if (id.isEmpty() || hashSalt.isEmpty())
215         return emptyString();
216
217     SHA1 sha1;
218
219     addStringToSHA1(sha1, id);
220     addStringToSHA1(sha1, hashSalt);
221     
222     SHA1::Digest digest;
223     sha1.computeHash(digest);
224     
225     return SHA1::hexDigest(digest).data();
226 }
227
228 std::optional<CaptureDevice> RealtimeMediaSourceCenter::captureDeviceWithUniqueID(const String& uniqueID, const String& idHashSalt)
229 {
230     for (auto& device : getMediaStreamDevices()) {
231         if (uniqueID == hashStringWithSalt(device.persistentId(), idHashSalt))
232             return device;
233     }
234
235     return std::nullopt;
236 }
237
238 ExceptionOr<void> RealtimeMediaSourceCenter::setDeviceEnabled(const String& id, bool enabled)
239 {
240     for (auto& captureDevice : getMediaStreamDevices()) {
241         if (id == captureDevice.persistentId()) {
242             if (enabled != captureDevice.enabled()) {
243                 captureDevice.setEnabled(enabled);
244                 captureDevicesChanged();
245             }
246
247             return { };
248         }
249     }
250
251     return Exception { NOT_FOUND_ERR };
252 }
253
254 RealtimeMediaSourceCenter::DevicesChangedObserverToken RealtimeMediaSourceCenter::addDevicesChangedObserver(std::function<void()>&& observer)
255 {
256     static DevicesChangedObserverToken nextToken = 0;
257     observerMap().set(++nextToken, WTFMove(observer));
258     return nextToken;
259 }
260
261 void RealtimeMediaSourceCenter::removeDevicesChangedObserver(DevicesChangedObserverToken token)
262 {
263     bool wasRemoved = observerMap().remove(token);
264     ASSERT_UNUSED(wasRemoved, wasRemoved);
265 }
266
267 void RealtimeMediaSourceCenter::captureDevicesChanged()
268 {
269     // Copy the hash map because the observer callback may call back in and modify the map.
270     auto callbacks = observerMap();
271     for (auto& it : callbacks)
272         it.value();
273 }
274
275 void RealtimeMediaSourceCenter::validateRequestConstraints(ValidConstraintsHandler&& validHandler, InvalidConstraintsHandler&& invalidHandler, const MediaConstraints& audioConstraints, const MediaConstraints& videoConstraints, String&& deviceIdentifierHashSalt)
276 {
277     struct DeviceInfo {
278         unsigned fitnessScore;
279         String id;
280     };
281
282     struct {
283         bool operator()(const DeviceInfo& a, const DeviceInfo& b)
284         {
285             return a.fitnessScore < b.fitnessScore;
286         }
287     } sortBasedOnFitnessScore;
288
289     Vector<DeviceInfo> audioDeviceInfo;
290     Vector<DeviceInfo> videoDeviceInfo;
291
292     String firstInvalidConstraint;
293     for (auto& device : getMediaStreamDevices()) {
294         if (!device.enabled())
295             continue;
296
297         String invalidConstraint;
298         CaptureSourceOrError sourceOrError;
299         if (device.type() == CaptureDevice::DeviceType::Video && videoConstraints.isValid) {
300             auto sourceOrError = videoFactory().createVideoCaptureSource(device.persistentId(), nullptr);
301             if (sourceOrError && sourceOrError.captureSource->supportsConstraints(videoConstraints, invalidConstraint))
302                 videoDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device.persistentId()});
303         } else if (device.type() == CaptureDevice::DeviceType::Audio && audioConstraints.isValid) {
304             auto sourceOrError = audioFactory().createAudioCaptureSource(device.persistentId(), nullptr);
305             if (sourceOrError && sourceOrError.captureSource->supportsConstraints(audioConstraints, invalidConstraint))
306                 audioDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device.persistentId()});
307         }
308
309         if (!invalidConstraint.isEmpty() && firstInvalidConstraint.isEmpty())
310             firstInvalidConstraint = invalidConstraint;
311     }
312
313     if ((audioConstraints.isValid && audioDeviceInfo.isEmpty()) || (videoConstraints.isValid && videoDeviceInfo.isEmpty())) {
314         invalidHandler(firstInvalidConstraint);
315         return;
316     }
317
318     Vector<String> audioSourceIds;
319     if (!audioDeviceInfo.isEmpty()) {
320         audioSourceIds.reserveInitialCapacity(audioDeviceInfo.size());
321         std::sort(audioDeviceInfo.begin(), audioDeviceInfo.end(), sortBasedOnFitnessScore);
322         for (auto& info : audioDeviceInfo)
323             audioSourceIds.uncheckedAppend(WTFMove(info.id));
324     }
325
326     Vector<String> videoSourceIds;
327     if (!videoDeviceInfo.isEmpty()) {
328         videoSourceIds.reserveInitialCapacity(videoDeviceInfo.size());
329         std::sort(videoDeviceInfo.begin(), videoDeviceInfo.end(), sortBasedOnFitnessScore);
330         for (auto& info : videoDeviceInfo)
331             videoSourceIds.uncheckedAppend(WTFMove(info.id));
332     }
333
334     validHandler(WTFMove(audioSourceIds), WTFMove(videoSourceIds), WTFMove(deviceIdentifierHashSalt));
335 }
336
337 void RealtimeMediaSourceCenter::setVisibility(bool isVisible)
338 {
339     videoFactory().setVisibility(isVisible);
340 }
341
342 } // namespace WebCore
343
344 #endif // ENABLE(MEDIA_STREAM)