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 "LibWebRTCProvider.h"
28
29#if USE(LIBWEBRTC)
30#include "LibWebRTCAudioModule.h"
31#include "Logging.h"
32#include "RTCRtpCapabilities.h"
33#include <dlfcn.h>
34
35ALLOW_UNUSED_PARAMETERS_BEGIN
36
37#include <webrtc/api/asyncresolverfactory.h>
38#include <webrtc/api/audio_codecs/builtin_audio_decoder_factory.h>
39#include <webrtc/api/audio_codecs/builtin_audio_encoder_factory.h>
40#include <webrtc/api/create_peerconnection_factory.h>
41#include <webrtc/api/peerconnectionfactoryproxy.h>
42#include <webrtc/modules/audio_processing/include/audio_processing.h>
43#include <webrtc/p2p/base/basicpacketsocketfactory.h>
44#include <webrtc/p2p/client/basicportallocator.h>
45#include <webrtc/pc/peerconnectionfactory.h>
46#include <webrtc/rtc_base/physicalsocketserver.h>
47
48ALLOW_UNUSED_PARAMETERS_END
49
50#include <wtf/Function.h>
51#include <wtf/NeverDestroyed.h>
52#endif
53
54namespace WebCore {
55
56#if !USE(LIBWEBRTC)
57UniqueRef<LibWebRTCProvider> LibWebRTCProvider::create()
58{
59 return makeUniqueRef<LibWebRTCProvider>();
60}
61
62bool LibWebRTCProvider::webRTCAvailable()
63{
64 return false;
65}
66#endif
67
68void LibWebRTCProvider::setActive(bool)
69{
70}
71
72#if USE(LIBWEBRTC)
73static inline rtc::SocketAddress prepareSocketAddress(const rtc::SocketAddress& address, bool disableNonLocalhostConnections)
74{
75 auto result = address;
76 if (disableNonLocalhostConnections)
77 result.SetIP("127.0.0.1");
78 return result;
79}
80
81class BasicPacketSocketFactory : public rtc::BasicPacketSocketFactory {
82public:
83 explicit BasicPacketSocketFactory(rtc::Thread& networkThread)
84 : m_socketFactory(makeUniqueRef<rtc::BasicPacketSocketFactory>(&networkThread))
85 {
86 }
87
88 void setDisableNonLocalhostConnections(bool disableNonLocalhostConnections) { m_disableNonLocalhostConnections = disableNonLocalhostConnections; }
89
90 rtc::AsyncPacketSocket* CreateUdpSocket(const rtc::SocketAddress& address, uint16_t minPort, uint16_t maxPort) final
91 {
92 return m_socketFactory->CreateUdpSocket(prepareSocketAddress(address, m_disableNonLocalhostConnections), minPort, maxPort);
93 }
94
95 rtc::AsyncPacketSocket* CreateServerTcpSocket(const rtc::SocketAddress& address, uint16_t minPort, uint16_t maxPort, int options) final
96 {
97 return m_socketFactory->CreateServerTcpSocket(prepareSocketAddress(address, m_disableNonLocalhostConnections), minPort, maxPort, options);
98 }
99
100 rtc::AsyncPacketSocket* CreateClientTcpSocket(const rtc::SocketAddress& localAddress, const rtc::SocketAddress& remoteAddress, const rtc::ProxyInfo& info, const std::string& name, int options)
101 {
102 return m_socketFactory->CreateClientTcpSocket(prepareSocketAddress(localAddress, m_disableNonLocalhostConnections), remoteAddress, info, name, options);
103 }
104
105private:
106 bool m_disableNonLocalhostConnections { false };
107 UniqueRef<rtc::BasicPacketSocketFactory> m_socketFactory;
108};
109
110struct PeerConnectionFactoryAndThreads : public rtc::MessageHandler {
111 std::unique_ptr<rtc::Thread> networkThread;
112 std::unique_ptr<rtc::Thread> signalingThread;
113 bool networkThreadWithSocketServer { false };
114 std::unique_ptr<LibWebRTCAudioModule> audioDeviceModule;
115 std::unique_ptr<rtc::NetworkManager> networkManager;
116 std::unique_ptr<BasicPacketSocketFactory> packetSocketFactory;
117 std::unique_ptr<rtc::RTCCertificateGenerator> certificateGenerator;
118
119private:
120 void OnMessage(rtc::Message*);
121};
122
123static void doReleaseLogging(rtc::LoggingSeverity severity, const char* message)
124{
125#if RELEASE_LOG_DISABLED
126 UNUSED_PARAM(severity);
127 UNUSED_PARAM(message);
128#else
129 if (severity == rtc::LS_ERROR)
130 RELEASE_LOG_ERROR(WebRTC, "LibWebRTC error: %{public}s", message);
131 else
132 RELEASE_LOG(WebRTC, "LibWebRTC message: %{public}s", message);
133#endif
134}
135
136static void setLogging(rtc::LoggingSeverity level)
137{
138 rtc::LogMessage::SetLogOutput(level, (level == rtc::LS_NONE) ? nullptr : doReleaseLogging);
139}
140
141static rtc::LoggingSeverity computeLogLevel()
142{
143#if defined(NDEBUG)
144#if !LOG_DISABLED || !RELEASE_LOG_DISABLED
145 if (LogWebRTC.state != WTFLogChannelState::On)
146 return rtc::LS_ERROR;
147
148 switch (LogWebRTC.level) {
149 case WTFLogLevel::Always:
150 case WTFLogLevel::Error:
151 return rtc::LS_ERROR;
152 case WTFLogLevel::Warning:
153 return rtc::LS_WARNING;
154 case WTFLogLevel::Info:
155 return rtc::LS_INFO;
156 case WTFLogLevel::Debug:
157 return rtc::LS_VERBOSE;
158 }
159#else
160 return rtc::LS_NONE;
161#endif
162#else
163 return (LogWebRTC.state != WTFLogChannelState::On) ? rtc::LS_WARNING : rtc::LS_INFO;
164#endif
165}
166
167static void initializePeerConnectionFactoryAndThreads(PeerConnectionFactoryAndThreads& factoryAndThreads)
168{
169 ASSERT(!factoryAndThreads.networkThread);
170
171 factoryAndThreads.networkThread = factoryAndThreads.networkThreadWithSocketServer ? rtc::Thread::CreateWithSocketServer() : rtc::Thread::Create();
172 factoryAndThreads.networkThread->SetName("WebKitWebRTCNetwork", nullptr);
173 bool result = factoryAndThreads.networkThread->Start();
174 ASSERT_UNUSED(result, result);
175
176 factoryAndThreads.signalingThread = rtc::Thread::Create();
177 factoryAndThreads.signalingThread->SetName("WebKitWebRTCSignaling", nullptr);
178
179 result = factoryAndThreads.signalingThread->Start();
180 ASSERT(result);
181
182 factoryAndThreads.audioDeviceModule = std::make_unique<LibWebRTCAudioModule>();
183}
184
185static inline PeerConnectionFactoryAndThreads& staticFactoryAndThreads()
186{
187 static NeverDestroyed<PeerConnectionFactoryAndThreads> factoryAndThreads;
188 return factoryAndThreads.get();
189}
190
191static inline PeerConnectionFactoryAndThreads& getStaticFactoryAndThreads(bool useNetworkThreadWithSocketServer)
192{
193 auto& factoryAndThreads = staticFactoryAndThreads();
194
195 ASSERT(!factoryAndThreads.networkThread || factoryAndThreads.networkThreadWithSocketServer == useNetworkThreadWithSocketServer);
196
197 if (!factoryAndThreads.networkThread) {
198 factoryAndThreads.networkThreadWithSocketServer = useNetworkThreadWithSocketServer;
199 initializePeerConnectionFactoryAndThreads(factoryAndThreads);
200 }
201 return factoryAndThreads;
202}
203
204struct ThreadMessageData : public rtc::MessageData {
205 ThreadMessageData(Function<void()>&& callback)
206 : callback(WTFMove(callback))
207 { }
208 Function<void()> callback;
209};
210
211void PeerConnectionFactoryAndThreads::OnMessage(rtc::Message* message)
212{
213 ASSERT(message->message_id == 1);
214 auto* data = static_cast<ThreadMessageData*>(message->pdata);
215 data->callback();
216 delete data;
217}
218
219void LibWebRTCProvider::callOnWebRTCNetworkThread(Function<void()>&& callback)
220{
221 PeerConnectionFactoryAndThreads& threads = staticFactoryAndThreads();
222 threads.networkThread->Post(RTC_FROM_HERE, &threads, 1, new ThreadMessageData(WTFMove(callback)));
223}
224
225void LibWebRTCProvider::callOnWebRTCSignalingThread(Function<void()>&& callback)
226{
227 PeerConnectionFactoryAndThreads& threads = staticFactoryAndThreads();
228 threads.signalingThread->Post(RTC_FROM_HERE, &threads, 1, new ThreadMessageData(WTFMove(callback)));
229}
230
231void LibWebRTCProvider::setEnableLogging(bool enableLogging)
232{
233 if (!m_enableLogging)
234 return;
235 m_enableLogging = enableLogging;
236 setLogging(enableLogging ? computeLogLevel() : rtc::LS_NONE);
237}
238
239webrtc::PeerConnectionFactoryInterface* LibWebRTCProvider::factory()
240{
241 if (m_factory)
242 return m_factory.get();
243
244 if (!webRTCAvailable())
245 return nullptr;
246
247 auto& factoryAndThreads = getStaticFactoryAndThreads(m_useNetworkThreadWithSocketServer);
248
249 m_factory = createPeerConnectionFactory(factoryAndThreads.networkThread.get(), factoryAndThreads.networkThread.get(), factoryAndThreads.audioDeviceModule.get());
250
251 return m_factory;
252}
253
254rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> LibWebRTCProvider::createPeerConnectionFactory(rtc::Thread* networkThread, rtc::Thread* signalingThread, LibWebRTCAudioModule* audioModule)
255{
256 return webrtc::CreatePeerConnectionFactory(networkThread, networkThread, signalingThread, audioModule, webrtc::CreateBuiltinAudioEncoderFactory(), webrtc::CreateBuiltinAudioDecoderFactory(), createEncoderFactory(), createDecoderFactory(), nullptr, nullptr);
257}
258
259std::unique_ptr<webrtc::VideoDecoderFactory> LibWebRTCProvider::createDecoderFactory()
260{
261 return nullptr;
262}
263
264std::unique_ptr<webrtc::VideoEncoderFactory> LibWebRTCProvider::createEncoderFactory()
265{
266 return nullptr;
267}
268
269void LibWebRTCProvider::setPeerConnectionFactory(rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>&& factory)
270{
271 m_factory = webrtc::PeerConnectionFactoryProxy::Create(getStaticFactoryAndThreads(m_useNetworkThreadWithSocketServer).signalingThread.get(), WTFMove(factory));
272}
273
274void LibWebRTCProvider::disableEnumeratingAllNetworkInterfaces()
275{
276 m_enableEnumeratingAllNetworkInterfaces = false;
277}
278
279void LibWebRTCProvider::enableEnumeratingAllNetworkInterfaces()
280{
281 m_enableEnumeratingAllNetworkInterfaces = true;
282}
283
284rtc::scoped_refptr<webrtc::PeerConnectionInterface> LibWebRTCProvider::createPeerConnection(webrtc::PeerConnectionObserver& observer, webrtc::PeerConnectionInterface::RTCConfiguration&& configuration)
285{
286 // Default WK1 implementation.
287 ASSERT(m_useNetworkThreadWithSocketServer);
288 auto& factoryAndThreads = getStaticFactoryAndThreads(m_useNetworkThreadWithSocketServer);
289
290 if (!factoryAndThreads.networkManager)
291 factoryAndThreads.networkManager = std::make_unique<rtc::BasicNetworkManager>();
292
293 if (!factoryAndThreads.packetSocketFactory)
294 factoryAndThreads.packetSocketFactory = std::make_unique<BasicPacketSocketFactory>(*factoryAndThreads.networkThread);
295 factoryAndThreads.packetSocketFactory->setDisableNonLocalhostConnections(m_disableNonLocalhostConnections);
296
297 return createPeerConnection(observer, *factoryAndThreads.networkManager, *factoryAndThreads.packetSocketFactory, WTFMove(configuration), nullptr);
298}
299
300rtc::scoped_refptr<webrtc::PeerConnectionInterface> LibWebRTCProvider::createPeerConnection(webrtc::PeerConnectionObserver& observer, rtc::NetworkManager& networkManager, rtc::PacketSocketFactory& packetSocketFactory, webrtc::PeerConnectionInterface::RTCConfiguration&& configuration, std::unique_ptr<webrtc::AsyncResolverFactory>&& asyncResolveFactory)
301{
302 auto& factoryAndThreads = getStaticFactoryAndThreads(m_useNetworkThreadWithSocketServer);
303
304 std::unique_ptr<cricket::BasicPortAllocator> portAllocator;
305 factoryAndThreads.signalingThread->Invoke<void>(RTC_FROM_HERE, [&]() {
306 auto basicPortAllocator = std::make_unique<cricket::BasicPortAllocator>(&networkManager, &packetSocketFactory);
307 if (!m_enableEnumeratingAllNetworkInterfaces)
308 basicPortAllocator->set_flags(basicPortAllocator->flags() | cricket::PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION);
309 portAllocator = WTFMove(basicPortAllocator);
310 });
311
312 auto* factory = this->factory();
313 if (!factory)
314 return nullptr;
315
316 webrtc::PeerConnectionDependencies dependencies { &observer };
317 dependencies.allocator = WTFMove(portAllocator);
318 dependencies.async_resolver_factory = WTFMove(asyncResolveFactory);
319
320 return m_factory->CreatePeerConnection(configuration, WTFMove(dependencies));
321}
322
323rtc::RTCCertificateGenerator& LibWebRTCProvider::certificateGenerator()
324{
325 auto& factoryAndThreads = getStaticFactoryAndThreads(m_useNetworkThreadWithSocketServer);
326 if (!factoryAndThreads.certificateGenerator)
327 factoryAndThreads.certificateGenerator = std::make_unique<rtc::RTCCertificateGenerator>(factoryAndThreads.signalingThread.get(), factoryAndThreads.networkThread.get());
328
329 return *factoryAndThreads.certificateGenerator;
330}
331
332static inline Optional<cricket::MediaType> typeFromKind(const String& kind)
333{
334 if (kind == "audio"_s)
335 return cricket::MediaType::MEDIA_TYPE_AUDIO;
336 if (kind == "video"_s)
337 return cricket::MediaType::MEDIA_TYPE_VIDEO;
338 return { };
339}
340
341static inline String fromStdString(const std::string& value)
342{
343 return String::fromUTF8(value.data(), value.length());
344}
345
346static inline Optional<uint16_t> toChannels(absl::optional<int> numChannels)
347{
348 if (!numChannels)
349 return { };
350 return static_cast<uint32_t>(*numChannels);
351}
352
353static inline RTCRtpCapabilities toRTCRtpCapabilities(const webrtc::RtpCapabilities& rtpCapabilities)
354{
355 RTCRtpCapabilities capabilities;
356
357 capabilities.codecs.reserveInitialCapacity(rtpCapabilities.codecs.size());
358 for (auto& codec : rtpCapabilities.codecs)
359 capabilities.codecs.uncheckedAppend(RTCRtpCapabilities::CodecCapability { fromStdString(codec.mime_type()), static_cast<uint32_t>(codec.clock_rate ? *codec.clock_rate : 0), toChannels(codec.num_channels), { } });
360
361 capabilities.headerExtensions.reserveInitialCapacity(rtpCapabilities.header_extensions.size());
362 for (auto& header : rtpCapabilities.header_extensions)
363 capabilities.headerExtensions.uncheckedAppend(RTCRtpCapabilities::HeaderExtensionCapability { fromStdString(header.uri) });
364
365 return capabilities;
366}
367
368Optional<RTCRtpCapabilities> LibWebRTCProvider::receiverCapabilities(const String& kind)
369{
370 auto mediaType = typeFromKind(kind);
371 if (!mediaType)
372 return { };
373
374 auto* factory = this->factory();
375 if (!factory)
376 return { };
377
378 return toRTCRtpCapabilities(factory->GetRtpReceiverCapabilities(*mediaType));
379}
380
381Optional<RTCRtpCapabilities> LibWebRTCProvider::senderCapabilities(const String& kind)
382{
383 auto mediaType = typeFromKind(kind);
384 if (!mediaType)
385 return { };
386
387 auto* factory = this->factory();
388 if (!factory)
389 return { };
390
391 return toRTCRtpCapabilities(factory->GetRtpSenderCapabilities(*mediaType));
392}
393
394#endif // USE(LIBWEBRTC)
395
396} // namespace WebCore
397