[WebRTC] Add support for libwebrtc negotiation needed event
[WebKit-https.git] / Source / WebCore / Modules / mediastream / libwebrtc / LibWebRTCPeerConnectionBackend.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc.
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'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26 #include "LibWebRTCPeerConnectionBackend.h"
27
28 #if USE(LIBWEBRTC)
29
30 #include "Document.h"
31 #include "IceCandidate.h"
32 #include "JSRTCStatsReport.h"
33 #include "LibWebRTCDataChannelHandler.h"
34 #include "LibWebRTCMediaEndpoint.h"
35 #include "MediaEndpointConfiguration.h"
36 #include "Page.h"
37 #include "RTCIceCandidate.h"
38 #include "RTCPeerConnection.h"
39 #include "RTCRtpReceiver.h"
40 #include "RTCSessionDescription.h"
41 #include "RealtimeIncomingAudioSource.h"
42 #include "RealtimeIncomingVideoSource.h"
43
44 namespace WebCore {
45
46 static std::unique_ptr<PeerConnectionBackend> createLibWebRTCPeerConnectionBackend(RTCPeerConnection& peerConnection)
47 {
48     return std::make_unique<LibWebRTCPeerConnectionBackend>(peerConnection);
49 }
50
51 CreatePeerConnectionBackend PeerConnectionBackend::create = createLibWebRTCPeerConnectionBackend;
52
53 static inline LibWebRTCProvider& libWebRTCProvider(RTCPeerConnection& peerConnection)
54 {
55     ASSERT(peerConnection.scriptExecutionContext()->isDocument());
56     auto* page = static_cast<Document*>(peerConnection.scriptExecutionContext())->page();
57     return page->libWebRTCProvider();
58 }
59
60 LibWebRTCPeerConnectionBackend::LibWebRTCPeerConnectionBackend(RTCPeerConnection& peerConnection)
61     : PeerConnectionBackend(peerConnection)
62     , m_endpoint(LibWebRTCMediaEndpoint::create(*this, libWebRTCProvider(peerConnection)))
63 {
64 }
65
66 LibWebRTCPeerConnectionBackend::~LibWebRTCPeerConnectionBackend()
67 {
68 }
69
70 static webrtc::PeerConnectionInterface::RTCConfiguration configurationFromMediaEndpointConfiguration(MediaEndpointConfiguration&& configuration)
71 {
72     webrtc::PeerConnectionInterface::RTCConfiguration rtcConfiguration(webrtc::PeerConnectionInterface::RTCConfigurationType::kAggressive);
73
74     if (configuration.iceTransportPolicy == PeerConnectionStates::IceTransportPolicy::Relay)
75         rtcConfiguration.type = webrtc::PeerConnectionInterface::kRelay;
76
77     if (configuration.bundlePolicy == PeerConnectionStates::BundlePolicy::MaxBundle)
78         rtcConfiguration.bundle_policy = webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle;
79     else if (configuration.bundlePolicy == PeerConnectionStates::BundlePolicy::MaxCompat)
80         rtcConfiguration.bundle_policy = webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat;
81
82     for (auto& server : configuration.iceServers) {
83         webrtc::PeerConnectionInterface::IceServer iceServer;
84         iceServer.username = server.username.utf8().data();
85         iceServer.password = server.credential.utf8().data();
86         for (auto& url : server.urls)
87             iceServer.urls.push_back({ url.string().utf8().data() });
88         rtcConfiguration.servers.push_back(WTFMove(iceServer));
89     }
90
91     return rtcConfiguration;
92 }
93
94 void LibWebRTCPeerConnectionBackend::setConfiguration(MediaEndpointConfiguration&& configuration)
95 {
96     m_endpoint->backend().SetConfiguration(configurationFromMediaEndpointConfiguration(WTFMove(configuration)));
97 }
98
99 void LibWebRTCPeerConnectionBackend::getStats(MediaStreamTrack* track, Ref<DeferredPromise>&& promise)
100 {
101     if (m_endpoint->isStopped())
102         return;
103
104     auto& statsPromise = promise.get();
105     m_statsPromises.add(&statsPromise, WTFMove(promise));
106     m_endpoint->getStats(track, statsPromise);
107 }
108
109 void LibWebRTCPeerConnectionBackend::getStatsSucceeded(const DeferredPromise& promise, Ref<RTCStatsReport>&& report)
110 {
111     auto statsPromise = m_statsPromises.take(&promise);
112     ASSERT(statsPromise);
113     statsPromise.value()->resolve<IDLInterface<RTCStatsReport>>(WTFMove(report));
114 }
115
116 void LibWebRTCPeerConnectionBackend::getStatsFailed(const DeferredPromise& promise, Exception&& exception)
117 {
118     auto statsPromise = m_statsPromises.take(&promise);
119     ASSERT(statsPromise);
120     statsPromise.value()->reject(WTFMove(exception));
121 }
122
123 void LibWebRTCPeerConnectionBackend::doSetLocalDescription(RTCSessionDescription& description)
124 {
125     m_endpoint->doSetLocalDescription(description);
126     if (!m_isLocalDescriptionSet) {
127         if (m_isRemoteDescriptionSet) {
128             while (m_pendingCandidates.size())
129                 m_endpoint->addIceCandidate(*m_pendingCandidates.takeLast().release());
130         }
131         m_isLocalDescriptionSet = true;
132     }
133 }
134
135 void LibWebRTCPeerConnectionBackend::doSetRemoteDescription(RTCSessionDescription& description)
136 {
137     m_endpoint->doSetRemoteDescription(description);
138     if (!m_isRemoteDescriptionSet) {
139         if (m_isLocalDescriptionSet) {
140             while (m_pendingCandidates.size())
141                 m_endpoint->addIceCandidate(*m_pendingCandidates.takeLast().release());
142         }
143         m_isRemoteDescriptionSet = true;
144     }
145 }
146
147 void LibWebRTCPeerConnectionBackend::doCreateOffer(RTCOfferOptions&&)
148 {
149     m_endpoint->doCreateOffer();
150 }
151
152 void LibWebRTCPeerConnectionBackend::doCreateAnswer(RTCAnswerOptions&&)
153 {
154     if (!m_isRemoteDescriptionSet) {
155         createAnswerFailed(Exception { INVALID_STATE_ERR, "No remote description set" });
156         return;
157     }
158     m_endpoint->doCreateAnswer();
159 }
160
161 void LibWebRTCPeerConnectionBackend::doStop()
162 {
163     m_endpoint->stop();
164 }
165
166 void LibWebRTCPeerConnectionBackend::doAddIceCandidate(RTCIceCandidate& candidate)
167 {
168     if (!m_isRemoteDescriptionSet) {
169         addIceCandidateFailed(Exception { INVALID_STATE_ERR, "No remote description set" });
170         return;
171     }
172
173     webrtc::SdpParseError error;
174     int sdpMLineIndex = candidate.sdpMLineIndex() ? candidate.sdpMLineIndex().value() : 0;
175     std::unique_ptr<webrtc::IceCandidateInterface> rtcCandidate(webrtc::CreateIceCandidate(candidate.sdpMid().utf8().data(), sdpMLineIndex, candidate.candidate().utf8().data(), &error));
176
177     if (!rtcCandidate) {
178         String message(error.description.data(), error.description.size());
179         addIceCandidateFailed(Exception { OperationError, WTFMove(message) });
180         return;
181     }
182
183     // libwebrtc does not like that ice candidates are set before the description.
184     if (!m_isLocalDescriptionSet || !m_isRemoteDescriptionSet)
185         m_pendingCandidates.append(WTFMove(rtcCandidate));
186     else if (!m_endpoint->addIceCandidate(*rtcCandidate.get())) {
187         ASSERT_NOT_REACHED();
188         addIceCandidateFailed(Exception { OperationError, ASCIILiteral("Failed to apply the received candidate") });
189         return;
190     }
191     addIceCandidateSucceeded();
192 }
193
194 void LibWebRTCPeerConnectionBackend::addAudioSource(Ref<RealtimeOutgoingAudioSource>&& source)
195 {
196     m_audioSources.append(WTFMove(source));
197 }
198
199 void LibWebRTCPeerConnectionBackend::addVideoSource(Ref<RealtimeOutgoingVideoSource>&& source)
200 {
201     m_videoSources.append(WTFMove(source));
202 }
203
204 Ref<RTCRtpReceiver> LibWebRTCPeerConnectionBackend::createReceiver(const String&, const String& trackKind, const String& trackId)
205 {
206     // FIXME: We need to create a source that will get fueled once we will receive OnAddStream.
207     // For the moment, we create an empty one.
208     auto remoteTrackPrivate = (trackKind == "audio") ? MediaStreamTrackPrivate::create(RealtimeIncomingAudioSource::create(nullptr, String(trackId))) : MediaStreamTrackPrivate::create(RealtimeIncomingVideoSource::create(nullptr, String(trackId)));
209     auto remoteTrack = MediaStreamTrack::create(*m_peerConnection.scriptExecutionContext(), WTFMove(remoteTrackPrivate));
210
211     return RTCRtpReceiver::create(WTFMove(remoteTrack));
212 }
213
214 std::unique_ptr<RTCDataChannelHandler> LibWebRTCPeerConnectionBackend::createDataChannelHandler(const String& label, const RTCDataChannelInit& options)
215 {
216     return m_endpoint->createDataChannel(label, options);
217 }
218
219 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::localDescription() const
220 {
221     return m_endpoint->localDescription();
222 }
223
224 RefPtr<RTCSessionDescription> LibWebRTCPeerConnectionBackend::remoteDescription() const
225 {
226     return m_endpoint->remoteDescription();
227 }
228
229 } // namespace WebCore
230
231 #endif // USE(LIBWEBRTC)