e2c5bf70a26724fd057c9a6ae461ad5ada53f9e0
[WebKit-https.git] / Source / WebCore / Modules / mediastream / MediaDevicesRequest.cpp
1 /*
2  * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26
27 #include "config.h"
28 #include "MediaDevicesRequest.h"
29
30 #if ENABLE(MEDIA_STREAM)
31
32 #include "CaptureDevice.h"
33 #include "Document.h"
34 #include "Frame.h"
35 #include "JSMediaDeviceInfo.h"
36 #include "MediaDevicesEnumerationRequest.h"
37 #include "RealtimeMediaSourceCenter.h"
38 #include "SecurityOrigin.h"
39 #include "UserMediaController.h"
40 #include <wtf/MainThread.h>
41 #include <wtf/SHA1.h>
42
43 namespace WebCore {
44
45 inline MediaDevicesRequest::MediaDevicesRequest(Document& document, MediaDevices::EnumerateDevicesPromise&& promise)
46     : ContextDestructionObserver(&document)
47     , m_promise(WTFMove(promise))
48 {
49 }
50
51 Ref<MediaDevicesRequest> MediaDevicesRequest::create(Document& document, MediaDevices::EnumerateDevicesPromise&& promise)
52 {
53     return adoptRef(*new MediaDevicesRequest(document, WTFMove(promise)));
54 }
55
56 MediaDevicesRequest::~MediaDevicesRequest()
57 {
58     // This should only get destroyed after the enumeration request has completed or has been canceled.
59     ASSERT(!m_enumerationRequest || m_enumerationRequest->wasCanceled());
60 }
61
62 SecurityOrigin* MediaDevicesRequest::securityOrigin() const
63 {
64     if (scriptExecutionContext())
65         return scriptExecutionContext()->securityOrigin();
66
67     return nullptr;
68 }
69
70 void MediaDevicesRequest::contextDestroyed()
71 {
72     // The call to m_enumerationRequest->cancel() might delete this.
73     auto protectedThis = makeRef(*this);
74
75     if (m_enumerationRequest) {
76         m_enumerationRequest->cancel();
77         m_enumerationRequest = nullptr;
78     }
79     ContextDestructionObserver::contextDestroyed();
80 }
81
82 void MediaDevicesRequest::filterDeviceList(Vector<Ref<MediaDeviceInfo>>& devices)
83 {
84 #if !PLATFORM(COCOA)
85     UNUSED_PARAM(devices);
86 #else
87
88 #if PLATFORM(IOS)
89     static const int defaultCameraCount = 2;
90 #endif
91 #if PLATFORM(MAC)
92     static const int defaultCameraCount = 1;
93 #endif
94     static const int defaultMicrophoneCount = 1;
95
96     int cameraCount = 0;
97     int microphoneCount = 0;
98     devices.removeAllMatching([&](const Ref<MediaDeviceInfo>& device) -> bool {
99         if (device->kind() == MediaDeviceInfo::Kind::Videoinput && ++cameraCount > defaultCameraCount)
100             return true;
101         if (device->kind() == MediaDeviceInfo::Kind::Audioinput && ++microphoneCount > defaultMicrophoneCount)
102             return true;
103
104         return false;
105     });
106
107 #endif
108 }
109
110 void MediaDevicesRequest::start()
111 {
112     // This lambda keeps |this| alive until the request completes or is canceled.
113     auto completion = [this, protectedThis = makeRef(*this)] (const Vector<CaptureDevice>& captureDevices, const String& deviceIdentifierHashSalt, bool originHasPersistentAccess) mutable {
114
115         m_enumerationRequest = nullptr;
116
117         if (!scriptExecutionContext())
118             return;
119
120         Document& document = downcast<Document>(*scriptExecutionContext());
121         document.setDeviceIDHashSalt(deviceIdentifierHashSalt);
122
123         Vector<Ref<MediaDeviceInfo>> devices;
124         for (auto& deviceInfo : captureDevices) {
125             auto label = emptyString();
126             if (originHasPersistentAccess || document.hasHadCaptureMediaStreamTrack())
127                 label = deviceInfo.label();
128
129             auto id = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(deviceInfo.persistentId(), deviceIdentifierHashSalt);
130             if (id.isEmpty())
131                 continue;
132
133             auto groupId = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(deviceInfo.groupId(), deviceIdentifierHashSalt);
134             auto deviceType = deviceInfo.type() == CaptureDevice::DeviceType::Microphone ? MediaDeviceInfo::Kind::Audioinput : MediaDeviceInfo::Kind::Videoinput;
135             devices.append(MediaDeviceInfo::create(scriptExecutionContext(), label, id, groupId, deviceType));
136         }
137
138         if (!originHasPersistentAccess && !document.hasHadCaptureMediaStreamTrack())
139             filterDeviceList(devices);
140
141         callOnMainThread([protectedThis = makeRef(*this), devices = WTFMove(devices)]() mutable {
142             protectedThis->m_promise.resolve(devices);
143         });
144     };
145
146     m_enumerationRequest = MediaDevicesEnumerationRequest::create(*downcast<Document>(scriptExecutionContext()), WTFMove(completion));
147     m_enumerationRequest->start();
148 }
149
150 } // namespace WebCore
151
152 #endif // ENABLE(MEDIA_STREAM)