Make WebRTC logging happen in Release
[WebKit-https.git] / Source / WebCore / Modules / mediastream / PeerConnectionBackend.cpp
1 /*
2  * Copyright (C) 2015 Ericsson AB. All rights reserved.
3  * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer
13  *    in the documentation and/or other materials provided with the
14  *    distribution.
15  * 3. Neither the name of Ericsson nor the names of its contributors
16  *    may be used to endorse or promote products derived from this
17  *    software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "PeerConnectionBackend.h"
34
35 #if ENABLE(WEB_RTC)
36
37 #include "EventNames.h"
38 #include "JSRTCSessionDescription.h"
39 #include "Logging.h"
40 #include "RTCIceCandidate.h"
41 #include "RTCPeerConnection.h"
42 #include "RTCPeerConnectionIceEvent.h"
43 #include <wtf/text/StringBuilder.h>
44
45 namespace WebCore {
46
47 void PeerConnectionBackend::createOffer(RTCOfferOptions&& options, PeerConnection::SessionDescriptionPromise&& promise)
48 {
49     ASSERT(!m_offerAnswerPromise);
50     ASSERT(!m_peerConnection.isClosed());
51
52     m_offerAnswerPromise = WTFMove(promise);
53     doCreateOffer(WTFMove(options));
54 }
55
56 void PeerConnectionBackend::createOfferSucceeded(String&& sdp)
57 {
58     ASSERT(isMainThread());
59     RELEASE_LOG(WebRTC, "Creating offer succeeded:\n%s\n", sdp.utf8().data());
60
61     if (m_peerConnection.isClosed())
62         return;
63
64     ASSERT(m_offerAnswerPromise);
65     m_offerAnswerPromise->resolve(RTCSessionDescription::create(RTCSdpType::Offer, WTFMove(sdp)));
66     m_offerAnswerPromise = std::nullopt;
67 }
68
69 void PeerConnectionBackend::createOfferFailed(Exception&& exception)
70 {
71     ASSERT(isMainThread());
72     RELEASE_LOG(WebRTC, "Creating offer failed:\n%s\n", exception.message().utf8().data());
73
74     if (m_peerConnection.isClosed())
75         return;
76
77     ASSERT(m_offerAnswerPromise);
78     m_offerAnswerPromise->reject(WTFMove(exception));
79     m_offerAnswerPromise = std::nullopt;
80 }
81
82 void PeerConnectionBackend::createAnswer(RTCAnswerOptions&& options, PeerConnection::SessionDescriptionPromise&& promise)
83 {
84     ASSERT(!m_offerAnswerPromise);
85     ASSERT(!m_peerConnection.isClosed());
86
87     m_offerAnswerPromise = WTFMove(promise);
88     doCreateAnswer(WTFMove(options));
89 }
90
91 void PeerConnectionBackend::createAnswerSucceeded(String&& sdp)
92 {
93     ASSERT(isMainThread());
94     RELEASE_LOG(WebRTC, "Creating answer succeeded:\n%s\n", sdp.utf8().data());
95     
96     if (m_peerConnection.isClosed())
97         return;
98
99     ASSERT(m_offerAnswerPromise);
100     m_offerAnswerPromise->resolve(RTCSessionDescription::create(RTCSdpType::Answer, WTFMove(sdp)));
101     m_offerAnswerPromise = std::nullopt;
102 }
103
104 void PeerConnectionBackend::createAnswerFailed(Exception&& exception)
105 {
106     ASSERT(isMainThread());
107     RELEASE_LOG(WebRTC, "Creating answer failed:\n%s\n", exception.message().utf8().data());
108
109     if (m_peerConnection.isClosed())
110         return;
111
112     ASSERT(m_offerAnswerPromise);
113     m_offerAnswerPromise->reject(WTFMove(exception));
114     m_offerAnswerPromise = std::nullopt;
115 }
116
117 static inline bool isLocalDescriptionTypeValidForState(RTCSdpType type, RTCSignalingState state)
118 {
119     switch (state) {
120     case RTCSignalingState::Stable:
121         return type == RTCSdpType::Offer;
122     case RTCSignalingState::HaveLocalOffer:
123         return type == RTCSdpType::Offer;
124     case RTCSignalingState::HaveRemoteOffer:
125         return type == RTCSdpType::Answer || type == RTCSdpType::Pranswer;
126     case RTCSignalingState::HaveLocalPranswer:
127         return type == RTCSdpType::Answer || type == RTCSdpType::Pranswer;
128     default:
129         return false;
130     };
131
132     ASSERT_NOT_REACHED();
133     return false;
134 }
135
136 void PeerConnectionBackend::setLocalDescription(RTCSessionDescription& sessionDescription, DOMPromiseDeferred<void>&& promise)
137 {
138     ASSERT(!m_peerConnection.isClosed());
139
140     if (!isLocalDescriptionTypeValidForState(sessionDescription.type(), m_peerConnection.signalingState())) {
141         promise.reject(INVALID_STATE_ERR, "Description type incompatible with current signaling state");
142         return;
143     }
144
145     m_setDescriptionPromise = WTFMove(promise);
146     doSetLocalDescription(sessionDescription);
147 }
148
149 void PeerConnectionBackend::setLocalDescriptionSucceeded()
150 {
151     ASSERT(isMainThread());
152     RELEASE_LOG(WebRTC, "Setting local description succeeded\n");
153
154     if (m_peerConnection.isClosed())
155         return;
156
157     ASSERT(m_setDescriptionPromise);
158
159     m_setDescriptionPromise->resolve();
160     m_setDescriptionPromise = std::nullopt;
161 }
162
163 void PeerConnectionBackend::setLocalDescriptionFailed(Exception&& exception)
164 {
165     ASSERT(isMainThread());
166     RELEASE_LOG(WebRTC, "Setting local description failed:\n%s\n", exception.message().utf8().data());
167
168     if (m_peerConnection.isClosed())
169         return;
170
171     ASSERT(m_setDescriptionPromise);
172
173     m_setDescriptionPromise->reject(WTFMove(exception));
174     m_setDescriptionPromise = std::nullopt;
175 }
176
177 static inline bool isRemoteDescriptionTypeValidForState(RTCSdpType type, RTCSignalingState state)
178 {
179     switch (state) {
180     case RTCSignalingState::Stable:
181         return type == RTCSdpType::Offer;
182     case RTCSignalingState::HaveLocalOffer:
183         return type == RTCSdpType::Answer || type == RTCSdpType::Pranswer;
184     case RTCSignalingState::HaveRemoteOffer:
185         return type == RTCSdpType::Offer;
186     case RTCSignalingState::HaveRemotePranswer:
187         return type == RTCSdpType::Answer || type == RTCSdpType::Pranswer;
188     default:
189         return false;
190     };
191
192     ASSERT_NOT_REACHED();
193     return false;
194 }
195
196 void PeerConnectionBackend::setRemoteDescription(RTCSessionDescription& sessionDescription, DOMPromiseDeferred<void>&& promise)
197 {
198     ASSERT(!m_peerConnection.isClosed());
199
200     if (!isRemoteDescriptionTypeValidForState(sessionDescription.type(), m_peerConnection.signalingState())) {
201         promise.reject(INVALID_STATE_ERR, "Description type incompatible with current signaling state");
202         return;
203     }
204
205     m_setDescriptionPromise = WTFMove(promise);
206     doSetRemoteDescription(sessionDescription);
207 }
208
209 void PeerConnectionBackend::setRemoteDescriptionSucceeded()
210 {
211     ASSERT(isMainThread());
212     RELEASE_LOG(WebRTC, "Setting remote description succeeded\n");
213
214     if (m_peerConnection.isClosed())
215         return;
216
217     ASSERT(m_setDescriptionPromise);
218
219     m_setDescriptionPromise->resolve();
220     m_setDescriptionPromise = std::nullopt;
221 }
222
223 void PeerConnectionBackend::setRemoteDescriptionFailed(Exception&& exception)
224 {
225     ASSERT(isMainThread());
226     RELEASE_LOG(WebRTC, "Setting remote description failed:\n%s\n", exception.message().utf8().data());
227
228     if (m_peerConnection.isClosed())
229         return;
230
231     ASSERT(m_setDescriptionPromise);
232
233     m_setDescriptionPromise->reject(WTFMove(exception));
234     m_setDescriptionPromise = std::nullopt;
235 }
236
237 void PeerConnectionBackend::addIceCandidate(RTCIceCandidate* iceCandidate, DOMPromiseDeferred<void>&& promise)
238 {
239     ASSERT(!m_peerConnection.isClosed());
240
241     if (!iceCandidate) {
242         endOfIceCandidates(WTFMove(promise));
243         return;
244     }
245
246     // FIXME: As per https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addicecandidate(), this check should be done before enqueuing the task.
247     if (iceCandidate->sdpMid().isNull() && !iceCandidate->sdpMLineIndex()) {
248         promise.reject(Exception { TypeError, ASCIILiteral("Trying to add a candidate that is missing both sdpMid and sdpMLineIndex") });
249         return;
250     }
251     m_addIceCandidatePromise = WTFMove(promise);
252     doAddIceCandidate(*iceCandidate);
253 }
254
255 void PeerConnectionBackend::addIceCandidateSucceeded()
256 {
257     ASSERT(isMainThread());
258     RELEASE_LOG(WebRTC, "Adding ice candidate succeeded\n");
259
260     if (m_peerConnection.isClosed())
261         return;
262
263     // FIXME: Update remote description and set ICE connection state to checking if not already done so.
264     ASSERT(m_addIceCandidatePromise);
265
266     m_addIceCandidatePromise->resolve();
267     m_addIceCandidatePromise = std::nullopt;
268 }
269
270 void PeerConnectionBackend::addIceCandidateFailed(Exception&& exception)
271 {
272     ASSERT(isMainThread());
273     RELEASE_LOG(WebRTC, "Adding ice candidate failed:\n%s\n", exception.message().utf8().data());
274
275     if (m_peerConnection.isClosed())
276         return;
277
278     ASSERT(m_addIceCandidatePromise);
279
280     m_addIceCandidatePromise->reject(WTFMove(exception));
281     m_addIceCandidatePromise = std::nullopt;
282 }
283
284 void PeerConnectionBackend::fireICECandidateEvent(RefPtr<RTCIceCandidate>&& candidate)
285 {
286     ASSERT(isMainThread());
287
288     m_peerConnection.fireEvent(RTCPeerConnectionIceEvent::create(false, false, WTFMove(candidate)));
289 }
290
291 void PeerConnectionBackend::enableICECandidateFiltering()
292 {
293     m_shouldFilterICECandidates = true;
294 }
295
296 void PeerConnectionBackend::disableICECandidateFiltering()
297 {
298     m_shouldFilterICECandidates = false;
299     for (auto& pendingICECandidate : m_pendingICECandidates)
300         fireICECandidateEvent(RTCIceCandidate::create(WTFMove(pendingICECandidate.sdp), WTFMove(pendingICECandidate.mid), 0));
301     m_pendingICECandidates.clear();
302 }
303
304 static inline String filterICECandidate(String&& sdp)
305 {
306     ASSERT(!sdp.contains(" host "));
307
308     if (!sdp.contains(" raddr "))
309         return WTFMove(sdp);
310
311     Vector<String> items;
312     sdp.split(' ', items);
313
314     bool skipNextItem = false;
315     bool isFirst = true;
316     StringBuilder filteredSDP;
317     for (auto& item : items) {
318         if (skipNextItem) {
319             skipNextItem = false;
320             continue;
321         }
322         if (item == "raddr" || item == "rport") {
323             skipNextItem = true;
324             continue;
325         }
326         if (isFirst)
327             isFirst = false;
328         else
329             filteredSDP.append(" ");
330         filteredSDP.append(item);
331     }
332     return filteredSDP.toString();
333 }
334
335 void PeerConnectionBackend::newICECandidate(String&& sdp, String&& mid)
336 {
337     RELEASE_LOG(WebRTC, "Gathered ice candidate:\n%s\n", sdp.utf8().data());
338
339     if (!m_shouldFilterICECandidates) {
340         fireICECandidateEvent(RTCIceCandidate::create(WTFMove(sdp), WTFMove(mid), 0));
341         return;
342     }
343     if (sdp.contains(" host ")) {
344         m_pendingICECandidates.append(PendingICECandidate { WTFMove(sdp), WTFMove(mid)});
345         return;
346     }
347     fireICECandidateEvent(RTCIceCandidate::create(filterICECandidate(WTFMove(sdp)), WTFMove(mid), 0));
348 }
349
350 void PeerConnectionBackend::doneGatheringCandidates()
351 {
352     ASSERT(isMainThread());
353     RELEASE_LOG(WebRTC, "Finished ice candidate gathering\n");
354
355     m_peerConnection.fireEvent(RTCPeerConnectionIceEvent::create(false, false, nullptr));
356     m_peerConnection.updateIceGatheringState(RTCIceGatheringState::Complete);
357 }
358
359 void PeerConnectionBackend::updateSignalingState(RTCSignalingState newSignalingState)
360 {
361     ASSERT(isMainThread());
362
363     if (newSignalingState != m_peerConnection.signalingState()) {
364         m_peerConnection.setSignalingState(newSignalingState);
365         m_peerConnection.fireEvent(Event::create(eventNames().signalingstatechangeEvent, false, false));
366     }
367 }
368
369 void PeerConnectionBackend::stop()
370 {
371     m_offerAnswerPromise = std::nullopt;
372     m_setDescriptionPromise = std::nullopt;
373     m_addIceCandidatePromise = std::nullopt;
374
375     doStop();
376 }
377
378 void PeerConnectionBackend::markAsNeedingNegotiation()
379 {
380     if (m_negotiationNeeded)
381         return;
382     
383     m_negotiationNeeded = true;
384     
385     if (m_peerConnection.signalingState() == RTCSignalingState::Stable)
386         m_peerConnection.scheduleNegotiationNeededEvent();
387 }
388
389 } // namespace WebCore
390
391 #endif // ENABLE(WEB_RTC)