7c7f6677494baf3b563c883c1ae211badd14b1dc
[WebKit-https.git] / Source / WebKit / WebProcess / cocoa / UserMediaCaptureManager.cpp
1 /*
2  * Copyright (C) 2017-2018 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "UserMediaCaptureManager.h"
28
29 #if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
30
31 #include "SharedRingBufferStorage.h"
32 #include "UserMediaCaptureManagerMessages.h"
33 #include "UserMediaCaptureManagerProxyMessages.h"
34 #include "WebCoreArgumentCoders.h"
35 #include "WebProcess.h"
36 #include "WebProcessCreationParameters.h"
37 #include <WebCore/CaptureDevice.h>
38 #include <WebCore/MediaConstraints.h>
39 #include <WebCore/RealtimeMediaSourceCenter.h>
40 #include <WebCore/WebAudioBufferList.h>
41 #include <WebCore/WebAudioSourceProviderAVFObjC.h>
42
43 namespace WebKit {
44 using namespace WebCore;
45
46 static uint64_t nextSessionID()
47 {
48     static uint64_t nextID = 0;
49     return ++nextID;
50 }
51
52 class UserMediaCaptureManager::Source : public RealtimeMediaSource {
53 public:
54     Source(const String& sourceID, Type type, const String& name, uint64_t id, UserMediaCaptureManager& manager)
55         : RealtimeMediaSource(sourceID, type, name)
56         , m_id(id)
57         , m_manager(manager)
58         , m_ringBuffer(makeUniqueRef<SharedRingBufferStorage>(nullptr))
59     {
60     }
61
62     ~Source()
63     {
64         storage().invalidate();
65     }
66
67     SharedRingBufferStorage& storage() { return static_cast<SharedRingBufferStorage&>(m_ringBuffer.storage()); }
68
69     const RealtimeMediaSourceCapabilities& capabilities() final
70     {
71         if (!m_capabilities)
72             m_capabilities = m_manager.capabilities(m_id);
73         return m_capabilities.value();
74     }
75
76     const RealtimeMediaSourceSettings& settings() final { return m_settings; }
77     void setSettings(RealtimeMediaSourceSettings&& settings)
78     {
79         auto changed = m_settings.difference(settings);
80         m_settings = WTFMove(settings);
81         notifySettingsDidChangeObservers(changed);
82     }
83
84     const CAAudioStreamDescription& description() const { return m_description; }
85     void setStorage(const SharedMemory::Handle& handle, const WebCore::CAAudioStreamDescription& description, uint64_t numberOfFrames)
86     {
87         m_description = description;
88
89         if (handle.isNull()) {
90             m_ringBuffer.deallocate();
91             storage().setReadOnly(false);
92             storage().setStorage(nullptr);
93             return;
94         }
95
96         RefPtr<SharedMemory> memory = SharedMemory::map(handle, SharedMemory::Protection::ReadOnly);
97         storage().setStorage(WTFMove(memory));
98         storage().setReadOnly(true);
99
100         m_ringBuffer.allocate(description, numberOfFrames);
101     }
102
103     void setRingBufferFrameBounds(uint64_t startFrame, uint64_t endFrame)
104     {
105         m_ringBuffer.setCurrentFrameBounds(startFrame, endFrame);
106     }
107
108     void audioSamplesAvailable(MediaTime time, uint64_t numberOfFrames)
109     {
110         WebAudioBufferList audioData(m_description, numberOfFrames);
111         m_ringBuffer.fetch(audioData.list(), numberOfFrames, time.timeValue());
112
113         RealtimeMediaSource::audioSamplesAvailable(time, audioData, m_description, numberOfFrames);
114     }
115
116     void applyConstraintsSucceeded(const WebCore::RealtimeMediaSourceSettings& settings)
117     {
118         auto callbacks = m_pendingApplyConstraintsCallbacks.takeFirst();
119         setSettings(WebCore::RealtimeMediaSourceSettings(settings));
120         callbacks.successHandler();
121     }
122
123     void applyConstraintsFailed(const String& failedConstraint, const String& errorMessage)
124     {
125         auto callbacks = m_pendingApplyConstraintsCallbacks.takeFirst();
126         callbacks.failureHandler(failedConstraint, errorMessage);
127     }
128
129 private:
130     void startProducingData() final { m_manager.startProducingData(m_id); }
131     void stopProducingData() final { m_manager.stopProducingData(m_id); }
132     bool isCaptureSource() const final { return true; }
133
134     // RealtimeMediaSource
135     void beginConfiguration() final { }
136     void commitConfiguration() final { }
137
138     void applyConstraints(const WebCore::MediaConstraints& constraints, SuccessHandler&& successHandler, FailureHandler&& failureHandler) final {
139         m_manager.applyConstraints(m_id, constraints);
140         m_pendingApplyConstraintsCallbacks.append({ WTFMove(successHandler), WTFMove(failureHandler)});
141     }
142
143     uint64_t m_id;
144     UserMediaCaptureManager& m_manager;
145     mutable std::optional<RealtimeMediaSourceCapabilities> m_capabilities;
146     RealtimeMediaSourceSettings m_settings;
147     CAAudioStreamDescription m_description;
148     CARingBuffer m_ringBuffer;
149
150     struct ApplyConstraintsCallback {
151         SuccessHandler successHandler;
152         FailureHandler failureHandler;
153     };
154     Deque<ApplyConstraintsCallback> m_pendingApplyConstraintsCallbacks;
155 };
156
157 UserMediaCaptureManager::UserMediaCaptureManager(WebProcess& process)
158     : m_process(process)
159 {
160     m_process.addMessageReceiver(Messages::UserMediaCaptureManager::messageReceiverName(), *this);
161 }
162
163 UserMediaCaptureManager::~UserMediaCaptureManager()
164 {
165     RealtimeMediaSourceCenter::singleton().unsetAudioFactory(*this);
166     m_process.removeMessageReceiver(Messages::UserMediaCaptureManager::messageReceiverName());
167 }
168
169 const char* UserMediaCaptureManager::supplementName()
170 {
171     return "UserMediaCaptureManager";
172 }
173
174 void UserMediaCaptureManager::initialize(const WebProcessCreationParameters& parameters)
175 {
176     if (parameters.shouldCaptureAudioInUIProcess)
177         RealtimeMediaSourceCenter::singleton().setAudioFactory(*this);
178 }
179
180 WebCore::CaptureSourceOrError UserMediaCaptureManager::createCaptureSource(const CaptureDevice& device, WebCore::RealtimeMediaSource::Type sourceType, const WebCore::MediaConstraints* constraints)
181 {
182     if (!constraints)
183         return { };
184
185     uint64_t id = nextSessionID();
186     RealtimeMediaSourceSettings settings;
187     String errorMessage;
188     bool succeeded;
189     if (!m_process.sendSync(Messages::UserMediaCaptureManagerProxy::CreateMediaSourceForCaptureDeviceWithConstraints(id, device, sourceType, *constraints), Messages::UserMediaCaptureManagerProxy::CreateMediaSourceForCaptureDeviceWithConstraints::Reply(succeeded, errorMessage, settings), 0))
190         return WTFMove(errorMessage);
191
192     auto source = adoptRef(*new Source(String::number(id), sourceType, settings.label(), id, *this));
193     source->setSettings(WTFMove(settings));
194     m_sources.set(id, source.copyRef());
195     return WebCore::CaptureSourceOrError(WTFMove(source));
196 }
197
198 void UserMediaCaptureManager::sourceStopped(uint64_t id)
199 {
200     ASSERT(m_sources.contains(id));
201     m_sources.get(id)->stop();
202 }
203
204 void UserMediaCaptureManager::captureFailed(uint64_t id)
205 {
206     ASSERT(m_sources.contains(id));
207     m_sources.get(id)->captureFailed();
208 }
209
210 void UserMediaCaptureManager::sourceMutedChanged(uint64_t id, bool muted)
211 {
212     ASSERT(m_sources.contains(id));
213     m_sources.get(id)->setMuted(muted);
214 }
215
216 void UserMediaCaptureManager::sourceSettingsChanged(uint64_t id, const RealtimeMediaSourceSettings& settings)
217 {
218     ASSERT(m_sources.contains(id));
219     m_sources.get(id)->setSettings(RealtimeMediaSourceSettings(settings));
220 }
221
222 void UserMediaCaptureManager::storageChanged(uint64_t id, const SharedMemory::Handle& handle, const WebCore::CAAudioStreamDescription& description, uint64_t numberOfFrames)
223 {
224     ASSERT(m_sources.contains(id));
225     m_sources.get(id)->setStorage(handle, description, numberOfFrames);
226 }
227
228 void UserMediaCaptureManager::ringBufferFrameBoundsChanged(uint64_t id, uint64_t startFrame, uint64_t endFrame)
229 {
230     ASSERT(m_sources.contains(id));
231     m_sources.get(id)->setRingBufferFrameBounds(startFrame, endFrame);
232 }
233
234 void UserMediaCaptureManager::audioSamplesAvailable(uint64_t id, MediaTime time, uint64_t numberOfFrames, uint64_t startFrame, uint64_t endFrame)
235 {
236     ASSERT(m_sources.contains(id));
237     auto& source = *m_sources.get(id);
238     source.setRingBufferFrameBounds(startFrame, endFrame);
239     source.audioSamplesAvailable(time, numberOfFrames);
240 }
241
242 void UserMediaCaptureManager::startProducingData(uint64_t id)
243 {
244     m_process.send(Messages::UserMediaCaptureManagerProxy::StartProducingData(id), 0);
245 }
246
247 void UserMediaCaptureManager::stopProducingData(uint64_t id)
248 {
249     m_process.send(Messages::UserMediaCaptureManagerProxy::StopProducingData(id), 0);
250 }
251
252 WebCore::RealtimeMediaSourceCapabilities UserMediaCaptureManager::capabilities(uint64_t id)
253 {
254     WebCore::RealtimeMediaSourceCapabilities capabilities;
255     m_process.sendSync(Messages::UserMediaCaptureManagerProxy::Capabilities(id), Messages::UserMediaCaptureManagerProxy::Capabilities::Reply(capabilities), 0);
256     return capabilities;
257 }
258
259 void UserMediaCaptureManager::setMuted(uint64_t id, bool muted)
260 {
261     m_process.send(Messages::UserMediaCaptureManagerProxy::SetMuted(id, muted), 0);
262 }
263
264 void UserMediaCaptureManager::applyConstraints(uint64_t id, const WebCore::MediaConstraints& constraints)
265 {
266     m_process.send(Messages::UserMediaCaptureManagerProxy::ApplyConstraints(id, constraints), 0);
267 }
268
269 void UserMediaCaptureManager::applyConstraintsSucceeded(uint64_t id, const WebCore::RealtimeMediaSourceSettings& settings)
270 {
271     ASSERT(m_sources.contains(id));
272     auto& source = *m_sources.get(id);
273     source.applyConstraintsSucceeded(settings);
274 }
275
276 void UserMediaCaptureManager::applyConstraintsFailed(uint64_t id, const String& failedConstraint, const String& message)
277 {
278     ASSERT(m_sources.contains(id));
279     auto& source = *m_sources.get(id);
280     source.applyConstraintsFailed(failedConstraint, message);
281 }
282
283 }
284
285 #endif