Rename Source/WebKit2 to Source/WebKit.
[WebKit-https.git] / Source / WebKit / UIProcess / Cocoa / UserMediaCaptureManagerProxy.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 "UserMediaCaptureManagerProxy.h"
28
29 #if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
30
31 #include "SharedRingBufferStorage.h"
32 #include "UserMediaCaptureManagerMessages.h"
33 #include "WebCoreArgumentCoders.h"
34 #include "WebProcessProxy.h"
35 #include <WebCore/CARingBuffer.h>
36 #include <WebCore/MediaConstraints.h>
37 #include <WebCore/RealtimeMediaSourceCenter.h>
38 #include <WebCore/WebAudioBufferList.h>
39 #include <wtf/UniqueRef.h>
40
41 using namespace WebCore;
42
43 namespace WebKit {
44
45 class UserMediaCaptureManagerProxy::SourceProxy : public RealtimeMediaSource::Observer, public SharedRingBufferStorage::Client {
46 public:
47     SourceProxy(uint64_t id, UserMediaCaptureManagerProxy& manager, Ref<RealtimeMediaSource>&& source)
48         : m_id(id)
49         , m_manager(manager)
50         , m_source(WTFMove(source))
51         , m_ringBuffer(makeUniqueRef<SharedRingBufferStorage>(makeUniqueRef<SharedRingBufferStorage>(this)))
52     {
53         m_source->addObserver(*this);
54     }
55
56     ~SourceProxy()
57     {
58         storage().invalidate();
59         m_source->removeObserver(*this);
60     }
61
62     RealtimeMediaSource& source() { return m_source; }
63     SharedRingBufferStorage& storage() { return static_cast<SharedRingBufferStorage&>(m_ringBuffer.storage()); }
64     CAAudioStreamDescription& description() { return m_description; }
65     int64_t numberOfFrames() { return m_numberOfFrames; }
66
67     void sourceStopped() final {
68         m_manager.process().send(Messages::UserMediaCaptureManager::SourceStopped(m_id), 0);
69     }
70
71     void sourceMutedChanged() final {
72         m_manager.process().send(Messages::UserMediaCaptureManager::SourceMutedChanged(m_id, m_source->muted()), 0);
73     }
74
75     void sourceSettingsChanged() final {
76         m_manager.process().send(Messages::UserMediaCaptureManager::SourceSettingsChanged(m_id, m_source->settings()), 0);
77     }
78
79     void audioSamplesAvailable(const MediaTime& time, const PlatformAudioData& audioData, const AudioStreamDescription& description, size_t numberOfFrames) final {
80         if (m_description != description) {
81             ASSERT(description.platformDescription().type == PlatformDescription::CAAudioStreamBasicType);
82             m_description = *WTF::get<const AudioStreamBasicDescription*>(description.platformDescription().description);
83
84             // Allocate a ring buffer large enough to contain 2 seconds of audio.
85             m_numberOfFrames = m_description.sampleRate() * 2;
86             m_ringBuffer.allocate(m_description.streamDescription(), m_numberOfFrames);
87         }
88
89         ASSERT(is<WebAudioBufferList>(audioData));
90         m_ringBuffer.store(downcast<WebAudioBufferList>(audioData).list(), numberOfFrames, time.timeValue());
91         uint64_t startFrame;
92         uint64_t endFrame;
93         m_ringBuffer.getCurrentFrameBounds(startFrame, endFrame);
94         m_manager.process().send(Messages::UserMediaCaptureManager::AudioSamplesAvailable(m_id, time, numberOfFrames, startFrame, endFrame), 0);
95     }
96
97     void storageChanged(SharedMemory* storage) final {
98         SharedMemory::Handle handle;
99         if (storage)
100             storage->createHandle(handle, SharedMemory::Protection::ReadOnly);
101         m_manager.process().send(Messages::UserMediaCaptureManager::StorageChanged(m_id, handle, m_description, m_numberOfFrames), 0);
102     }
103
104 protected:
105     uint64_t m_id;
106     UserMediaCaptureManagerProxy& m_manager;
107     Ref<RealtimeMediaSource> m_source;
108     CARingBuffer m_ringBuffer;
109     CAAudioStreamDescription m_description { };
110     int64_t m_numberOfFrames { 0 };
111 };
112
113 UserMediaCaptureManagerProxy::UserMediaCaptureManagerProxy(WebProcessProxy& process)
114     : m_process(process)
115 {
116     m_process.addMessageReceiver(Messages::UserMediaCaptureManagerProxy::messageReceiverName(), *this);
117 }
118
119 UserMediaCaptureManagerProxy::~UserMediaCaptureManagerProxy()
120 {
121     m_process.removeMessageReceiver(Messages::UserMediaCaptureManagerProxy::messageReceiverName());
122 }
123
124 void UserMediaCaptureManagerProxy::createMediaSourceForCaptureDeviceWithConstraints(uint64_t id, const String& deviceID, WebCore::RealtimeMediaSource::Type type, const MediaConstraints& constraints, bool& succeeded, String& invalidConstraints, WebCore::RealtimeMediaSourceSettings& settings)
125 {
126     CaptureSourceOrError sourceOrError;
127     switch (type) {
128     case WebCore::RealtimeMediaSource::Type::Audio:
129         sourceOrError = RealtimeMediaSourceCenter::singleton().audioFactory().createAudioCaptureSource(deviceID, &constraints);
130         break;
131     case WebCore::RealtimeMediaSource::Type::Video:
132         sourceOrError = RealtimeMediaSourceCenter::singleton().videoFactory().createVideoCaptureSource(deviceID, &constraints);
133         break;
134     case WebCore::RealtimeMediaSource::Type::None:
135         ASSERT_NOT_REACHED();
136         break;
137     }
138
139     succeeded = !!sourceOrError;
140     if (sourceOrError) {
141         auto source = sourceOrError.source();
142         settings = source->settings();
143         m_proxies.set(id, std::make_unique<SourceProxy>(id, *this, WTFMove(source)));
144     } else
145         invalidConstraints = WTFMove(sourceOrError.errorMessage);
146 }
147
148 void UserMediaCaptureManagerProxy::startProducingData(uint64_t id)
149 {
150     auto iter = m_proxies.find(id);
151     if (iter != m_proxies.end())
152         iter->value->source().start();
153 }
154
155 void UserMediaCaptureManagerProxy::stopProducingData(uint64_t id)
156 {
157     auto iter = m_proxies.find(id);
158     if (iter != m_proxies.end())
159         iter->value->source().stop();
160 }
161
162 void UserMediaCaptureManagerProxy::capabilities(uint64_t id, WebCore::RealtimeMediaSourceCapabilities& capabilities)
163 {
164     auto iter = m_proxies.find(id);
165     if (iter != m_proxies.end())
166         capabilities = iter->value->source().capabilities();
167 }
168
169 void UserMediaCaptureManagerProxy::setMuted(uint64_t id, bool muted)
170 {
171     auto iter = m_proxies.find(id);
172     if (iter != m_proxies.end())
173         iter->value->source().setMuted(muted);
174 }
175
176 void UserMediaCaptureManagerProxy::applyConstraints(uint64_t id, const WebCore::MediaConstraints& constraints)
177 {
178     auto iter = m_proxies.find(id);
179     if (iter == m_proxies.end())
180         return;
181
182     auto& source = iter->value->source();
183     auto result = source.applyConstraints(constraints);
184     if (!result)
185         m_process.send(Messages::UserMediaCaptureManager::ApplyConstraintsSucceeded(id, source.settings()), 0);
186     else
187         m_process.send(Messages::UserMediaCaptureManager::ApplyConstraintsFailed(id, result.value().first, result.value().second), 0);
188 }
189
190 }
191
192 #endif