d4ee1c4ed7698a83efccef57d9cece3756afb49b
[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     RefPtr<RealtimeMediaSourceCapabilities> capabilities() const final { return m_capabilities; }
70     void setCapabilities(RefPtr<RealtimeMediaSourceCapabilities> capabilities) { m_capabilities = capabilities; }
71
72     const RealtimeMediaSourceSettings& settings() const final { return m_settings; }
73     void setSettings(const RealtimeMediaSourceSettings& settings)
74     {
75         m_settings = settings;
76         settingsDidChange();
77     }
78
79     const CAAudioStreamDescription& description() const { return m_description; }
80     void setStorage(const SharedMemory::Handle& handle, const WebCore::CAAudioStreamDescription& description, uint64_t numberOfFrames)
81     {
82         m_description = description;
83         if (m_audioSourceProvider)
84             m_audioSourceProvider->prepare(&m_description.streamDescription());
85
86         if (handle.isNull()) {
87             m_ringBuffer.deallocate();
88             storage().setReadOnly(false);
89             storage().setStorage(nullptr);
90             return;
91         }
92
93         RefPtr<SharedMemory> memory = SharedMemory::map(handle, SharedMemory::Protection::ReadOnly);
94         storage().setStorage(WTFMove(memory));
95         storage().setReadOnly(true);
96
97         m_ringBuffer.allocate(description, numberOfFrames);
98     }
99
100     void setRingBufferFrameBounds(uint64_t startFrame, uint64_t endFrame)
101     {
102         m_ringBuffer.setCurrentFrameBounds(startFrame, endFrame);
103     }
104
105     void audioSamplesAvailable(MediaTime time, uint64_t numberOfFrames)
106     {
107         WebAudioBufferList audioData(m_description, numberOfFrames);
108         m_ringBuffer.fetch(audioData.list(), numberOfFrames, time.timeValue());
109
110         for (auto* observer : observers())
111             observer->audioSamplesAvailable(time, audioData, m_description, numberOfFrames);
112     }
113
114     void startProducingData() final { m_manager.startProducingData(m_id); }
115     void stopProducingData() final { m_manager.stopProducingData(m_id); }
116     bool isCaptureSource() const final { return true; }
117
118     AudioSourceProvider* audioSourceProvider() final {
119         if (!m_audioSourceProvider) {
120             m_audioSourceProvider = WebAudioSourceProviderAVFObjC::create(*this);
121             if (m_description.format() != AudioStreamDescription::None)
122                 m_audioSourceProvider->prepare(&m_description.streamDescription());
123         }
124         return m_audioSourceProvider.get();
125     }
126
127 private:
128     // RealtimeMediaSource
129     void beginConfiguration() final { }
130     void commitConfiguration() final { }
131
132     uint64_t m_id;
133     UserMediaCaptureManager& m_manager;
134     RefPtr<RealtimeMediaSourceCapabilities> m_capabilities;
135     RealtimeMediaSourceSettings m_settings;
136     CAAudioStreamDescription m_description;
137     CARingBuffer m_ringBuffer;
138     RefPtr<WebAudioSourceProviderAVFObjC> m_audioSourceProvider;
139 };
140
141 UserMediaCaptureManager::UserMediaCaptureManager(WebProcess* process)
142     : m_process(*process)
143 {
144     m_process.addMessageReceiver(Messages::UserMediaCaptureManager::messageReceiverName(), *this);
145 }
146
147 UserMediaCaptureManager::~UserMediaCaptureManager()
148 {
149     RealtimeMediaSourceCenter::singleton().unsetAudioFactory(*this);
150     m_process.removeMessageReceiver(Messages::UserMediaCaptureManager::messageReceiverName());
151 }
152
153 const char* UserMediaCaptureManager::supplementName()
154 {
155     return "UserMediaCaptureManager";
156 }
157
158 void UserMediaCaptureManager::initialize(const WebProcessCreationParameters& parameters)
159 {
160     if (parameters.shouldCaptureAudioInUIProcess)
161         RealtimeMediaSourceCenter::singleton().setAudioFactory(*this);
162 }
163
164 RefPtr<RealtimeMediaSource> UserMediaCaptureManager::createMediaSourceForCaptureDeviceWithConstraints(const CaptureDevice& device, const MediaConstraints* constraints, String& invalidConstraints)
165 {
166     if (!constraints)
167         return nullptr;
168
169     uint64_t id = nextSessionID();
170     MediaConstraintsData constraintsData;
171     constraintsData.mandatoryConstraints = constraints->mandatoryConstraints();
172     constraintsData.advancedConstraints = constraints->advancedConstraints();
173     constraintsData.isValid = constraints->isValid();
174     bool succeeded;
175
176     m_process.sendSync(Messages::UserMediaCaptureManagerProxy::CreateMediaSourceForCaptureDeviceWithConstraints(id, device, constraintsData), Messages::UserMediaCaptureManagerProxy::CreateMediaSourceForCaptureDeviceWithConstraints::Reply(succeeded, invalidConstraints), 0);
177
178     auto source = adoptRef(new Source(String::number(id), RealtimeMediaSource::Type::Audio, device.label(), id, *this));
179     m_sources.set(id, source);
180     return source;
181 }
182
183 void UserMediaCaptureManager::sourceStopped(uint64_t id)
184 {
185     ASSERT(m_sources.contains(id));
186     m_sources.get(id)->stop();
187 }
188
189 void UserMediaCaptureManager::sourceMutedChanged(uint64_t id, bool muted)
190 {
191     ASSERT(m_sources.contains(id));
192     m_sources.get(id)->setMuted(muted);
193 }
194
195 void UserMediaCaptureManager::sourceEnabledChanged(uint64_t id, bool enabled)
196 {
197     ASSERT(m_sources.contains(id));
198     m_sources.get(id)->setEnabled(enabled);
199 }
200
201 void UserMediaCaptureManager::sourceSettingsChanged(uint64_t id, const RealtimeMediaSourceSettings& settings)
202 {
203     ASSERT(m_sources.contains(id));
204     m_sources.get(id)->setSettings(settings);
205 }
206
207 void UserMediaCaptureManager::storageChanged(uint64_t id, const SharedMemory::Handle& handle, const WebCore::CAAudioStreamDescription& description, uint64_t numberOfFrames)
208 {
209     ASSERT(m_sources.contains(id));
210     m_sources.get(id)->setStorage(handle, description, numberOfFrames);
211 }
212
213 void UserMediaCaptureManager::ringBufferFrameBoundsChanged(uint64_t id, uint64_t startFrame, uint64_t endFrame)
214 {
215     ASSERT(m_sources.contains(id));
216     m_sources.get(id)->setRingBufferFrameBounds(startFrame, endFrame);
217 }
218
219 void UserMediaCaptureManager::audioSamplesAvailable(uint64_t id, MediaTime time, uint64_t numberOfFrames, uint64_t startFrame, uint64_t endFrame)
220 {
221     ASSERT(m_sources.contains(id));
222     auto& source = *m_sources.get(id);
223     source.setRingBufferFrameBounds(startFrame, endFrame);
224     source.audioSamplesAvailable(time, numberOfFrames);
225 }
226
227 void UserMediaCaptureManager::startProducingData(uint64_t id)
228 {
229     m_process.send(Messages::UserMediaCaptureManagerProxy::StartProducingData(id), 0);
230 }
231
232 void UserMediaCaptureManager::stopProducingData(uint64_t id)
233 {
234     m_process.send(Messages::UserMediaCaptureManagerProxy::StopProducingData(id), 0);
235 }
236
237 }
238
239 #endif