[MediaSource] Push capabilities across process boundary during UIProcess capture.
[WebKit-https.git] / Source / WebKit2 / WebProcess / cocoa / UserMediaCaptureManager.cpp
1 /*
2  * Copyright (C) 2017 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/MediaConstraintsImpl.h>
39 #include <WebCore/RealtimeMediaSourceCenter.h>
40 #include <WebCore/WebAudioBufferList.h>
41 #include <WebCore/WebAudioSourceProviderAVFObjC.h>
42
43 using namespace WebCore;
44
45 namespace WebKit {
46
47 static uint64_t nextSessionID()
48 {
49     static uint64_t nextID = 0;
50     return ++nextID;
51 }
52
53 class UserMediaCaptureManager::Source : public RealtimeMediaSource {
54 public:
55     Source(const String& sourceID, Type type, const String& name, uint64_t id, UserMediaCaptureManager& manager)
56         : RealtimeMediaSource(sourceID, type, name)
57         , m_id(id)
58         , m_manager(manager)
59         , m_ringBuffer(makeUniqueRef<SharedRingBufferStorage>(nullptr))
60     {
61     }
62
63     ~Source()
64     {
65         storage().invalidate();
66     }
67
68     SharedRingBufferStorage& storage() { return static_cast<SharedRingBufferStorage&>(m_ringBuffer.storage()); }
69     const RealtimeMediaSourceCapabilities& capabilities() const final {
70         if (!m_capabilities)
71             m_capabilities = m_manager.capabilities(m_id);
72         return m_capabilities.value();
73     }
74
75     const RealtimeMediaSourceSettings& settings() const final { return m_settings; }
76     void setSettings(const RealtimeMediaSourceSettings& settings)
77     {
78         m_settings = settings;
79         settingsDidChange();
80     }
81
82     const CAAudioStreamDescription& description() const { return m_description; }
83     void setStorage(const SharedMemory::Handle& handle, const WebCore::CAAudioStreamDescription& description, uint64_t numberOfFrames)
84     {
85         m_description = description;
86         if (m_audioSourceProvider)
87             m_audioSourceProvider->prepare(&m_description.streamDescription());
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         for (auto* observer : observers())
114             observer->audioSamplesAvailable(time, audioData, m_description, numberOfFrames);
115     }
116
117     void startProducingData() final { m_manager.startProducingData(m_id); }
118     void stopProducingData() final { m_manager.stopProducingData(m_id); }
119     bool isCaptureSource() const final { return true; }
120
121     AudioSourceProvider* audioSourceProvider() final {
122         if (!m_audioSourceProvider) {
123             m_audioSourceProvider = WebAudioSourceProviderAVFObjC::create(*this);
124             if (m_description.format() != AudioStreamDescription::None)
125                 m_audioSourceProvider->prepare(&m_description.streamDescription());
126         }
127         return m_audioSourceProvider.get();
128     }
129
130 private:
131     // RealtimeMediaSource
132     void beginConfiguration() final { }
133     void commitConfiguration() final { }
134
135     uint64_t m_id;
136     UserMediaCaptureManager& m_manager;
137     mutable std::optional<RealtimeMediaSourceCapabilities> m_capabilities;
138     RealtimeMediaSourceSettings m_settings;
139     CAAudioStreamDescription m_description;
140     CARingBuffer m_ringBuffer;
141     RefPtr<WebAudioSourceProviderAVFObjC> m_audioSourceProvider;
142 };
143
144 UserMediaCaptureManager::UserMediaCaptureManager(WebProcess* process)
145     : m_process(*process)
146 {
147     m_process.addMessageReceiver(Messages::UserMediaCaptureManager::messageReceiverName(), *this);
148 }
149
150 UserMediaCaptureManager::~UserMediaCaptureManager()
151 {
152     RealtimeMediaSourceCenter::singleton().unsetAudioFactory(*this);
153     m_process.removeMessageReceiver(Messages::UserMediaCaptureManager::messageReceiverName());
154 }
155
156 const char* UserMediaCaptureManager::supplementName()
157 {
158     return "UserMediaCaptureManager";
159 }
160
161 void UserMediaCaptureManager::initialize(const WebProcessCreationParameters& parameters)
162 {
163     if (parameters.shouldCaptureAudioInUIProcess)
164         RealtimeMediaSourceCenter::singleton().setAudioFactory(*this);
165 }
166
167 RefPtr<RealtimeMediaSource> UserMediaCaptureManager::createMediaSourceForCaptureDeviceWithConstraints(const CaptureDevice& device, const MediaConstraints* constraints, String& invalidConstraints)
168 {
169     if (!constraints)
170         return nullptr;
171
172     uint64_t id = nextSessionID();
173     MediaConstraintsData constraintsData;
174     constraintsData.mandatoryConstraints = constraints->mandatoryConstraints();
175     constraintsData.advancedConstraints = constraints->advancedConstraints();
176     constraintsData.isValid = constraints->isValid();
177     bool succeeded;
178
179     m_process.sendSync(Messages::UserMediaCaptureManagerProxy::CreateMediaSourceForCaptureDeviceWithConstraints(id, device, constraintsData), Messages::UserMediaCaptureManagerProxy::CreateMediaSourceForCaptureDeviceWithConstraints::Reply(succeeded, invalidConstraints), 0);
180
181     auto source = adoptRef(new Source(String::number(id), RealtimeMediaSource::Type::Audio, device.label(), id, *this));
182     m_sources.set(id, source);
183     return source;
184 }
185
186 void UserMediaCaptureManager::sourceStopped(uint64_t id)
187 {
188     ASSERT(m_sources.contains(id));
189     m_sources.get(id)->stop();
190 }
191
192 void UserMediaCaptureManager::sourceMutedChanged(uint64_t id, bool muted)
193 {
194     ASSERT(m_sources.contains(id));
195     m_sources.get(id)->setMuted(muted);
196 }
197
198 void UserMediaCaptureManager::sourceEnabledChanged(uint64_t id, bool enabled)
199 {
200     ASSERT(m_sources.contains(id));
201     m_sources.get(id)->setEnabled(enabled);
202 }
203
204 void UserMediaCaptureManager::sourceSettingsChanged(uint64_t id, const RealtimeMediaSourceSettings& settings)
205 {
206     ASSERT(m_sources.contains(id));
207     m_sources.get(id)->setSettings(settings);
208 }
209
210 void UserMediaCaptureManager::storageChanged(uint64_t id, const SharedMemory::Handle& handle, const WebCore::CAAudioStreamDescription& description, uint64_t numberOfFrames)
211 {
212     ASSERT(m_sources.contains(id));
213     m_sources.get(id)->setStorage(handle, description, numberOfFrames);
214 }
215
216 void UserMediaCaptureManager::ringBufferFrameBoundsChanged(uint64_t id, uint64_t startFrame, uint64_t endFrame)
217 {
218     ASSERT(m_sources.contains(id));
219     m_sources.get(id)->setRingBufferFrameBounds(startFrame, endFrame);
220 }
221
222 void UserMediaCaptureManager::audioSamplesAvailable(uint64_t id, MediaTime time, uint64_t numberOfFrames, uint64_t startFrame, uint64_t endFrame)
223 {
224     ASSERT(m_sources.contains(id));
225     auto& source = *m_sources.get(id);
226     source.setRingBufferFrameBounds(startFrame, endFrame);
227     source.audioSamplesAvailable(time, numberOfFrames);
228 }
229
230 void UserMediaCaptureManager::startProducingData(uint64_t id)
231 {
232     m_process.send(Messages::UserMediaCaptureManagerProxy::StartProducingData(id), 0);
233 }
234
235 void UserMediaCaptureManager::stopProducingData(uint64_t id)
236 {
237     m_process.send(Messages::UserMediaCaptureManagerProxy::StopProducingData(id), 0);
238 }
239
240 WebCore::RealtimeMediaSourceCapabilities&& UserMediaCaptureManager::capabilities(uint64_t id)
241 {
242     WebCore::RealtimeMediaSourceCapabilities capabilities;
243     m_process.sendSync(Messages::UserMediaCaptureManagerProxy::Capabilities(id), Messages::UserMediaCaptureManagerProxy::Capabilities::Reply(capabilities), 0);
244     return WTFMove(capabilities);
245 }
246
247 }
248
249 #endif