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