efa19adc72f4189ebb8940482601a5e6a3f82c1d
[WebKit-https.git] / Source / WebCore / Modules / mediastream / libwebrtc / LibWebRTCMediaEndpoint.cpp
1 /*
2  * Copyright (C) 2017-2018 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'' 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 "LibWebRTCMediaEndpoint.h"
27
28 #if USE(LIBWEBRTC)
29
30 #include "EventNames.h"
31 #include "JSRTCStatsReport.h"
32 #include "LibWebRTCDataChannelHandler.h"
33 #include "LibWebRTCPeerConnectionBackend.h"
34 #include "LibWebRTCProvider.h"
35 #include "LibWebRTCRtpReceiverBackend.h"
36 #include "LibWebRTCRtpSenderBackend.h"
37 #include "LibWebRTCStatsCollector.h"
38 #include "LibWebRTCUtils.h"
39 #include "Logging.h"
40 #include "NotImplemented.h"
41 #include "Performance.h"
42 #include "PlatformStrategies.h"
43 #include "RTCDataChannel.h"
44 #include "RTCDataChannelEvent.h"
45 #include "RTCOfferOptions.h"
46 #include "RTCPeerConnection.h"
47 #include "RTCSessionDescription.h"
48 #include "RTCStatsReport.h"
49 #include "RTCTrackEvent.h"
50 #include "RealtimeIncomingAudioSource.h"
51 #include "RealtimeIncomingVideoSource.h"
52 #include "RealtimeOutgoingAudioSource.h"
53 #include "RealtimeOutgoingVideoSource.h"
54 #include "RuntimeEnabledFeatures.h"
55 #include <webrtc/rtc_base/physicalsocketserver.h>
56 #include <webrtc/p2p/base/basicpacketsocketfactory.h>
57 #include <webrtc/p2p/client/basicportallocator.h>
58 #include <webrtc/pc/peerconnectionfactory.h>
59 #include <wtf/MainThread.h>
60
61 namespace WebCore {
62
63 LibWebRTCMediaEndpoint::LibWebRTCMediaEndpoint(LibWebRTCPeerConnectionBackend& peerConnection, LibWebRTCProvider& client)
64     : m_peerConnectionBackend(peerConnection)
65     , m_peerConnectionFactory(*client.factory())
66     , m_createSessionDescriptionObserver(*this)
67     , m_setLocalSessionDescriptionObserver(*this)
68     , m_setRemoteSessionDescriptionObserver(*this)
69     , m_statsLogTimer(*this, &LibWebRTCMediaEndpoint::gatherStatsForLogging)
70 #if !RELEASE_LOG_DISABLED
71     , m_logger(peerConnection.logger())
72     , m_logIdentifier(peerConnection.logIdentifier())
73 #endif
74 {
75     ASSERT(isMainThread());
76     ASSERT(client.factory());
77 }
78
79 bool LibWebRTCMediaEndpoint::setConfiguration(LibWebRTCProvider& client, webrtc::PeerConnectionInterface::RTCConfiguration&& configuration)
80 {
81     if (RuntimeEnabledFeatures::sharedFeatures().webRTCUnifiedPlanEnabled())
82         configuration.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
83
84     if (!m_backend) {
85         m_backend = client.createPeerConnection(*this, WTFMove(configuration));
86         return !!m_backend;
87     }
88     return m_backend->SetConfiguration(WTFMove(configuration));
89 }
90
91 static inline const char* sessionDescriptionType(RTCSdpType sdpType)
92 {
93     switch (sdpType) {
94     case RTCSdpType::Offer:
95         return "offer";
96     case RTCSdpType::Pranswer:
97         return "pranswer";
98     case RTCSdpType::Answer:
99         return "answer";
100     case RTCSdpType::Rollback:
101         return "rollback";
102     }
103
104     ASSERT_NOT_REACHED();
105     return "";
106 }
107
108 static inline RTCSdpType fromSessionDescriptionType(const webrtc::SessionDescriptionInterface& description)
109 {
110     auto type = description.type();
111     if (type == webrtc::SessionDescriptionInterface::kOffer)
112         return RTCSdpType::Offer;
113     if (type == webrtc::SessionDescriptionInterface::kAnswer)
114         return RTCSdpType::Answer;
115     ASSERT(type == webrtc::SessionDescriptionInterface::kPrAnswer);
116     return RTCSdpType::Pranswer;
117 }
118
119 static inline RefPtr<RTCSessionDescription> fromSessionDescription(const webrtc::SessionDescriptionInterface* description)
120 {
121     if (!description)
122         return nullptr;
123
124     std::string sdp;
125     description->ToString(&sdp);
126
127     return RTCSessionDescription::create(fromSessionDescriptionType(*description), fromStdString(sdp));
128 }
129
130 // FIXME: We might want to create a new object only if the session actually changed for all description getters.
131 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::currentLocalDescription() const
132 {
133     return m_backend ? fromSessionDescription(m_backend->current_local_description()) : nullptr;
134 }
135
136 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::currentRemoteDescription() const
137 {
138     return m_backend ? fromSessionDescription(m_backend->current_remote_description()) : nullptr;
139 }
140
141 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::pendingLocalDescription() const
142 {
143     return m_backend ? fromSessionDescription(m_backend->pending_local_description()) : nullptr;
144 }
145
146 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::pendingRemoteDescription() const
147 {
148     return m_backend ? fromSessionDescription(m_backend->pending_remote_description()) : nullptr;
149 }
150
151 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::localDescription() const
152 {
153     return m_backend ? fromSessionDescription(m_backend->local_description()) : nullptr;
154 }
155
156 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::remoteDescription() const
157 {
158     return m_backend ? fromSessionDescription(m_backend->remote_description()) : nullptr;
159 }
160
161 void LibWebRTCMediaEndpoint::doSetLocalDescription(RTCSessionDescription& description)
162 {
163     ASSERT(m_backend);
164
165     webrtc::SdpParseError error;
166     std::unique_ptr<webrtc::SessionDescriptionInterface> sessionDescription(webrtc::CreateSessionDescription(sessionDescriptionType(description.type()), description.sdp().utf8().data(), &error));
167
168     if (!sessionDescription) {
169         m_peerConnectionBackend.setLocalDescriptionFailed(Exception { OperationError, fromStdString(error.description) });
170         return;
171     }
172
173     // FIXME: See https://bugs.webkit.org/show_bug.cgi?id=173783. Remove this test once fixed at LibWebRTC level.
174     if (description.type() == RTCSdpType::Answer && !m_backend->pending_remote_description()) {
175         m_peerConnectionBackend.setLocalDescriptionFailed(Exception { InvalidStateError, "Failed to set local answer sdp: no pending remote description."_s });
176         return;
177     }
178
179     m_backend->SetLocalDescription(&m_setLocalSessionDescriptionObserver, sessionDescription.release());
180 }
181
182 void LibWebRTCMediaEndpoint::doSetRemoteDescription(RTCSessionDescription& description)
183 {
184     ASSERT(m_backend);
185
186     webrtc::SdpParseError error;
187     std::unique_ptr<webrtc::SessionDescriptionInterface> sessionDescription(webrtc::CreateSessionDescription(sessionDescriptionType(description.type()), description.sdp().utf8().data(), &error));
188     if (!sessionDescription) {
189         m_peerConnectionBackend.setRemoteDescriptionFailed(Exception { OperationError, fromStdString(error.description) });
190         return;
191     }
192     m_backend->SetRemoteDescription(&m_setRemoteSessionDescriptionObserver, sessionDescription.release());
193
194     startLoggingStats();
195 }
196
197 bool LibWebRTCMediaEndpoint::addTrack(LibWebRTCRtpSenderBackend& sender, MediaStreamTrack& track, const Vector<String>& mediaStreamIds)
198 {
199     ASSERT(m_backend);
200     ASSERT(!sender.rtcSender());
201
202     if (!RuntimeEnabledFeatures::sharedFeatures().webRTCUnifiedPlanEnabled()) {
203         String mediaStreamId = mediaStreamIds.isEmpty() ? createCanonicalUUIDString() : mediaStreamIds[0];
204         m_localStreams.ensure(mediaStreamId, [&] {
205             auto mediaStream = m_peerConnectionFactory.CreateLocalMediaStream(mediaStreamId.utf8().data());
206             m_backend->AddStream(mediaStream);
207             return mediaStream;
208         });
209     }
210
211     std::vector<std::string> ids;
212     for (auto& id : mediaStreamIds)
213         ids.push_back(id.utf8().data());
214
215     switch (track.privateTrack().type()) {
216     case RealtimeMediaSource::Type::Audio: {
217         auto audioSource = RealtimeOutgoingAudioSource::create(track.privateTrack());
218         auto audioTrack = m_peerConnectionFactory.CreateAudioTrack(track.id().utf8().data(), audioSource.ptr());
219         sender.setSource(WTFMove(audioSource));
220         auto rtpSender = m_backend->AddTrack(audioTrack.get(), WTFMove(ids));
221         if (!rtpSender.ok())
222             return false;
223         sender.setRTCSender(rtpSender.MoveValue());
224         return true;
225     }
226     case RealtimeMediaSource::Type::Video: {
227         auto videoSource = RealtimeOutgoingVideoSource::create(track.privateTrack());
228         auto videoTrack = m_peerConnectionFactory.CreateVideoTrack(track.id().utf8().data(), videoSource.ptr());
229         sender.setSource(WTFMove(videoSource));
230         auto rtpSender = m_backend->AddTrack(videoTrack.get(), WTFMove(ids));
231         if (!rtpSender.ok())
232             return false;
233         sender.setRTCSender(rtpSender.MoveValue());
234         return true;
235     }
236     case RealtimeMediaSource::Type::None:
237         ASSERT_NOT_REACHED();
238     }
239     return false;
240 }
241
242 void LibWebRTCMediaEndpoint::removeTrack(LibWebRTCRtpSenderBackend& sender)
243 {
244     ASSERT(m_backend);
245     m_backend->RemoveTrack(sender.rtcSender());
246 }
247
248 void LibWebRTCMediaEndpoint::doCreateOffer(const RTCOfferOptions& options)
249 {
250     ASSERT(m_backend);
251
252     m_isInitiator = true;
253     webrtc::PeerConnectionInterface::RTCOfferAnswerOptions rtcOptions;
254     rtcOptions.ice_restart = options.iceRestart;
255     rtcOptions.voice_activity_detection = options.voiceActivityDetection;
256
257     if (!RuntimeEnabledFeatures::sharedFeatures().webRTCUnifiedPlanEnabled()) {
258         if (m_peerConnectionBackend.shouldOfferAllowToReceive("audio"_s))
259             rtcOptions.offer_to_receive_audio = webrtc::PeerConnectionInterface::RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
260         if (m_peerConnectionBackend.shouldOfferAllowToReceive("video"_s))
261             rtcOptions.offer_to_receive_video = webrtc::PeerConnectionInterface::RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
262     }
263     m_backend->CreateOffer(&m_createSessionDescriptionObserver, rtcOptions);
264 }
265
266 void LibWebRTCMediaEndpoint::doCreateAnswer()
267 {
268     ASSERT(m_backend);
269
270     m_isInitiator = false;
271     m_backend->CreateAnswer(&m_createSessionDescriptionObserver, nullptr);
272 }
273
274 void LibWebRTCMediaEndpoint::getStats(MediaStreamTrack*, Ref<DeferredPromise>&& promise)
275 {
276     auto collector = LibWebRTCStatsCollector::create([promise = WTFMove(promise), protectedThis = makeRef(*this)](auto&& report) mutable {
277         ASSERT(isMainThread());
278         if (protectedThis->isStopped() || !report)
279             return false;
280
281         promise->resolve<IDLInterface<RTCStatsReport>>(report.releaseNonNull());
282         return true;
283     });
284     LibWebRTCProvider::callOnWebRTCSignalingThread([this, collector = WTFMove(collector)] {
285         if (m_backend)
286             m_backend->GetStats(collector.get());
287     });
288 }
289
290 static RTCSignalingState signalingState(webrtc::PeerConnectionInterface::SignalingState state)
291 {
292     switch (state) {
293     case webrtc::PeerConnectionInterface::kStable:
294         return RTCSignalingState::Stable;
295     case webrtc::PeerConnectionInterface::kHaveLocalOffer:
296         return RTCSignalingState::HaveLocalOffer;
297     case webrtc::PeerConnectionInterface::kHaveLocalPrAnswer:
298         return RTCSignalingState::HaveLocalPranswer;
299     case webrtc::PeerConnectionInterface::kHaveRemoteOffer:
300         return RTCSignalingState::HaveRemoteOffer;
301     case webrtc::PeerConnectionInterface::kHaveRemotePrAnswer:
302         return RTCSignalingState::HaveRemotePranswer;
303     case webrtc::PeerConnectionInterface::kClosed:
304         return RTCSignalingState::Stable;
305     }
306
307     ASSERT_NOT_REACHED();
308     return RTCSignalingState::Stable;
309 }
310
311 void LibWebRTCMediaEndpoint::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState rtcState)
312 {
313     auto state = signalingState(rtcState);
314     callOnMainThread([protectedThis = makeRef(*this), state] {
315         if (protectedThis->isStopped())
316             return;
317         protectedThis->m_peerConnectionBackend.updateSignalingState(state);
318     });
319 }
320
321 MediaStream& LibWebRTCMediaEndpoint::mediaStreamFromRTCStream(webrtc::MediaStreamInterface& rtcStream)
322 {
323     auto mediaStream = m_streams.ensure(&rtcStream, [&rtcStream, this] {
324         auto label = rtcStream.id();
325         return MediaStream::create(*m_peerConnectionBackend.connection().scriptExecutionContext(), MediaStreamPrivate::create({ }, fromStdString(label)));
326     });
327     return *mediaStream.iterator->value;
328 }
329
330 void LibWebRTCMediaEndpoint::addRemoteStream(webrtc::MediaStreamInterface&)
331 {
332 }
333
334 void LibWebRTCMediaEndpoint::addRemoteTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface>&& rtcReceiver, const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& rtcStreams)
335 {
336     ASSERT(rtcReceiver);
337     RefPtr<RTCRtpReceiver> receiver;
338     RefPtr<RealtimeMediaSource> remoteSource;
339
340     auto* rtcTrack = rtcReceiver->track().get();
341
342     switch (rtcReceiver->media_type()) {
343     case cricket::MEDIA_TYPE_DATA:
344         return;
345     case cricket::MEDIA_TYPE_AUDIO: {
346         rtc::scoped_refptr<webrtc::AudioTrackInterface> audioTrack = static_cast<webrtc::AudioTrackInterface*>(rtcTrack);
347         auto audioReceiver = m_peerConnectionBackend.audioReceiver(fromStdString(rtcTrack->id()));
348
349         receiver = WTFMove(audioReceiver.receiver);
350         audioReceiver.source->setSourceTrack(WTFMove(audioTrack));
351         break;
352     }
353     case cricket::MEDIA_TYPE_VIDEO: {
354         rtc::scoped_refptr<webrtc::VideoTrackInterface> videoTrack = static_cast<webrtc::VideoTrackInterface*>(rtcTrack);
355         auto videoReceiver = m_peerConnectionBackend.videoReceiver(fromStdString(rtcTrack->id()));
356
357         receiver = WTFMove(videoReceiver.receiver);
358         videoReceiver.source->setSourceTrack(WTFMove(videoTrack));
359         break;
360     }
361     }
362
363     receiver->setBackend(std::make_unique<LibWebRTCRtpReceiverBackend>(WTFMove(rtcReceiver)));
364     
365     auto* track = receiver->track();
366     ASSERT(track);
367
368     Vector<RefPtr<MediaStream>> streams;
369     for (auto& rtcStream : rtcStreams) {
370         auto& mediaStream = mediaStreamFromRTCStream(*rtcStream.get());
371         streams.append(&mediaStream);
372         mediaStream.addTrackFromPlatform(*track);
373     }
374     m_peerConnectionBackend.connection().fireEvent(RTCTrackEvent::create(eventNames().trackEvent,
375         Event::CanBubble::No, Event::IsCancelable::No, WTFMove(receiver), track, WTFMove(streams), nullptr));
376 }
377
378 void LibWebRTCMediaEndpoint::removeRemoteStream(webrtc::MediaStreamInterface& rtcStream)
379 {
380     bool removed = m_streams.remove(&rtcStream);
381     ASSERT_UNUSED(removed, removed);
382 }
383
384 void LibWebRTCMediaEndpoint::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)
385 {
386     callOnMainThread([protectedThis = makeRef(*this), stream = WTFMove(stream)] {
387         if (protectedThis->isStopped())
388             return;
389         ASSERT(stream);
390         protectedThis->addRemoteStream(*stream.get());
391     });
392 }
393
394 void LibWebRTCMediaEndpoint::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)
395 {
396     callOnMainThread([protectedThis = makeRef(*this), stream = WTFMove(stream)] {
397         if (protectedThis->isStopped())
398             return;
399         ASSERT(stream);
400         protectedThis->removeRemoteStream(*stream.get());
401     });
402 }
403
404 void LibWebRTCMediaEndpoint::OnAddTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver, const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& streams)
405 {
406     callOnMainThread([protectedThis = makeRef(*this), receiver = WTFMove(receiver), streams]() mutable {
407         if (protectedThis->isStopped())
408             return;
409         protectedThis->addRemoteTrack(WTFMove(receiver), streams);
410     });
411 }
412
413 std::unique_ptr<RTCDataChannelHandler> LibWebRTCMediaEndpoint::createDataChannel(const String& label, const RTCDataChannelInit& options)
414 {
415     auto init = LibWebRTCDataChannelHandler::fromRTCDataChannelInit(options);
416     auto channel = m_backend->CreateDataChannel(label.utf8().data(), &init);
417     return channel ? std::make_unique<LibWebRTCDataChannelHandler>(WTFMove(channel)) : nullptr;
418 }
419
420 void LibWebRTCMediaEndpoint::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel)
421 {
422     callOnMainThread([protectedThis = makeRef(*this), dataChannel = WTFMove(dataChannel)]() mutable {
423         if (protectedThis->isStopped())
424             return;
425         auto& connection = protectedThis->m_peerConnectionBackend.connection();
426         connection.fireEvent(LibWebRTCDataChannelHandler::channelEvent(*connection.scriptExecutionContext(), WTFMove(dataChannel)));
427     });
428 }
429
430 void LibWebRTCMediaEndpoint::stop()
431 {
432     if (!m_backend)
433         return;
434
435     stopLoggingStats();
436
437     m_backend->Close();
438     m_backend = nullptr;
439     m_streams.clear();
440 }
441
442 void LibWebRTCMediaEndpoint::OnRenegotiationNeeded()
443 {
444     callOnMainThread([protectedThis = makeRef(*this)] {
445         if (protectedThis->isStopped())
446             return;
447         protectedThis->m_peerConnectionBackend.markAsNeedingNegotiation();
448     });
449 }
450
451 static inline RTCIceConnectionState toRTCIceConnectionState(webrtc::PeerConnectionInterface::IceConnectionState state)
452 {
453     switch (state) {
454     case webrtc::PeerConnectionInterface::kIceConnectionNew:
455         return RTCIceConnectionState::New;
456     case webrtc::PeerConnectionInterface::kIceConnectionChecking:
457         return RTCIceConnectionState::Checking;
458     case webrtc::PeerConnectionInterface::kIceConnectionConnected:
459         return RTCIceConnectionState::Connected;
460     case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
461         return RTCIceConnectionState::Completed;
462     case webrtc::PeerConnectionInterface::kIceConnectionFailed:
463         return RTCIceConnectionState::Failed;
464     case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
465         return RTCIceConnectionState::Disconnected;
466     case webrtc::PeerConnectionInterface::kIceConnectionClosed:
467         return RTCIceConnectionState::Closed;
468     case webrtc::PeerConnectionInterface::kIceConnectionMax:
469         break;
470     }
471
472     ASSERT_NOT_REACHED();
473     return RTCIceConnectionState::New;
474 }
475
476 void LibWebRTCMediaEndpoint::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState state)
477 {
478     auto connectionState = toRTCIceConnectionState(state);
479     callOnMainThread([protectedThis = makeRef(*this), connectionState] {
480         if (protectedThis->isStopped())
481             return;
482         if (protectedThis->m_peerConnectionBackend.connection().iceConnectionState() != connectionState)
483             protectedThis->m_peerConnectionBackend.connection().updateIceConnectionState(connectionState);
484     });
485 }
486
487 void LibWebRTCMediaEndpoint::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState state)
488 {
489     callOnMainThread([protectedThis = makeRef(*this), state] {
490         if (protectedThis->isStopped())
491             return;
492         if (state == webrtc::PeerConnectionInterface::kIceGatheringComplete)
493             protectedThis->m_peerConnectionBackend.doneGatheringCandidates();
494         else if (state == webrtc::PeerConnectionInterface::kIceGatheringGathering)
495             protectedThis->m_peerConnectionBackend.connection().updateIceGatheringState(RTCIceGatheringState::Gathering);
496     });
497 }
498
499 void LibWebRTCMediaEndpoint::OnIceCandidate(const webrtc::IceCandidateInterface *rtcCandidate)
500 {
501     ASSERT(rtcCandidate);
502
503     std::string sdp;
504     rtcCandidate->ToString(&sdp);
505
506     auto sdpMLineIndex = safeCast<unsigned short>(rtcCandidate->sdp_mline_index());
507
508     callOnMainThread([protectedThis = makeRef(*this), mid = fromStdString(rtcCandidate->sdp_mid()), sdp = fromStdString(sdp), sdpMLineIndex, url = fromStdString(rtcCandidate->server_url())]() mutable {
509         if (protectedThis->isStopped())
510             return;
511         protectedThis->m_peerConnectionBackend.newICECandidate(WTFMove(sdp), WTFMove(mid), sdpMLineIndex, WTFMove(url));
512     });
513 }
514
515 void LibWebRTCMediaEndpoint::OnIceCandidatesRemoved(const std::vector<cricket::Candidate>&)
516 {
517     ASSERT_NOT_REACHED();
518 }
519
520 void LibWebRTCMediaEndpoint::createSessionDescriptionSucceeded(std::unique_ptr<webrtc::SessionDescriptionInterface>&& description)
521 {
522     std::string sdp;
523     description->ToString(&sdp);
524
525     callOnMainThread([protectedThis = makeRef(*this), sdp = fromStdString(sdp)]() mutable {
526         if (protectedThis->isStopped())
527             return;
528         if (protectedThis->m_isInitiator)
529             protectedThis->m_peerConnectionBackend.createOfferSucceeded(WTFMove(sdp));
530         else
531             protectedThis->m_peerConnectionBackend.createAnswerSucceeded(WTFMove(sdp));
532     });
533 }
534
535 void LibWebRTCMediaEndpoint::createSessionDescriptionFailed(const std::string& errorMessage)
536 {
537     callOnMainThread([protectedThis = makeRef(*this), error = fromStdString(errorMessage)] () mutable {
538         if (protectedThis->isStopped())
539             return;
540         if (protectedThis->m_isInitiator)
541             protectedThis->m_peerConnectionBackend.createOfferFailed(Exception { OperationError, WTFMove(error) });
542         else
543             protectedThis->m_peerConnectionBackend.createAnswerFailed(Exception { OperationError, WTFMove(error) });
544     });
545 }
546
547 void LibWebRTCMediaEndpoint::setLocalSessionDescriptionSucceeded()
548 {
549     callOnMainThread([protectedThis = makeRef(*this)] {
550         if (protectedThis->isStopped())
551             return;
552         protectedThis->m_peerConnectionBackend.setLocalDescriptionSucceeded();
553     });
554 }
555
556 void LibWebRTCMediaEndpoint::setLocalSessionDescriptionFailed(const std::string& errorMessage)
557 {
558     callOnMainThread([protectedThis = makeRef(*this), error = fromStdString(errorMessage)] () mutable {
559         if (protectedThis->isStopped())
560             return;
561         protectedThis->m_peerConnectionBackend.setLocalDescriptionFailed(Exception { OperationError, WTFMove(error) });
562     });
563 }
564
565 void LibWebRTCMediaEndpoint::setRemoteSessionDescriptionSucceeded()
566 {
567     callOnMainThread([protectedThis = makeRef(*this)] {
568         if (protectedThis->isStopped())
569             return;
570         protectedThis->m_peerConnectionBackend.setRemoteDescriptionSucceeded();
571     });
572 }
573
574 void LibWebRTCMediaEndpoint::setRemoteSessionDescriptionFailed(const std::string& errorMessage)
575 {
576     callOnMainThread([protectedThis = makeRef(*this), error = fromStdString(errorMessage)] () mutable {
577         if (protectedThis->isStopped())
578             return;
579         protectedThis->m_peerConnectionBackend.setRemoteDescriptionFailed(Exception { OperationError, WTFMove(error) });
580     });
581 }
582
583 void LibWebRTCMediaEndpoint::gatherStatsForLogging()
584 {
585     LibWebRTCProvider::callOnWebRTCSignalingThread([protectedThis = makeRef(*this)] {
586         if (protectedThis->m_backend)
587             protectedThis->m_backend->GetStats(protectedThis.ptr());
588     });
589 }
590
591 class RTCStatsLogger {
592 public:
593     explicit RTCStatsLogger(const webrtc::RTCStats& stats)
594         : m_stats(stats)
595     {
596     }
597
598     String toJSONString() const { return String(m_stats.ToJson().c_str()); }
599
600 private:
601     const webrtc::RTCStats& m_stats;
602 };
603
604 void LibWebRTCMediaEndpoint::OnStatsDelivered(const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report)
605 {
606 #if !RELEASE_LOG_DISABLED
607     int64_t timestamp = report->timestamp_us();
608     if (!m_statsFirstDeliveredTimestamp)
609         m_statsFirstDeliveredTimestamp = timestamp;
610
611     callOnMainThread([protectedThis = makeRef(*this), this, timestamp, report] {
612         if (m_statsLogTimer.repeatInterval() != statsLogInterval(timestamp)) {
613             m_statsLogTimer.stop();
614             m_statsLogTimer.startRepeating(statsLogInterval(timestamp));
615         }
616
617         for (auto iterator = report->begin(); iterator != report->end(); ++iterator) {
618             if (iterator->type() == webrtc::RTCCodecStats::kType)
619                 continue;
620
621             ALWAYS_LOG(Logger::LogSiteIdentifier("LibWebRTCMediaEndpoint", "OnStatsDelivered", logIdentifier()), RTCStatsLogger { *iterator });
622         }
623     });
624 #else
625     UNUSED_PARAM(report);
626 #endif
627 }
628
629 void LibWebRTCMediaEndpoint::startLoggingStats()
630 {
631 #if !RELEASE_LOG_DISABLED
632     if (m_statsLogTimer.isActive())
633         m_statsLogTimer.stop();
634     m_statsLogTimer.startRepeating(statsLogInterval(0));
635 #endif
636 }
637
638 void LibWebRTCMediaEndpoint::stopLoggingStats()
639 {
640     m_statsLogTimer.stop();
641 }
642
643 #if !RELEASE_LOG_DISABLED
644 WTFLogChannel& LibWebRTCMediaEndpoint::logChannel() const
645 {
646     return LogWebRTC;
647 }
648
649 Seconds LibWebRTCMediaEndpoint::statsLogInterval(int64_t reportTimestamp) const
650 {
651     if (logger().willLog(logChannel(), WTFLogLevelInfo))
652         return 2_s;
653
654     if (reportTimestamp - m_statsFirstDeliveredTimestamp > 15000000)
655         return 10_s;
656
657     return 4_s;
658 }
659 #endif
660
661 } // namespace WebCore
662
663 namespace WTF {
664
665 template<typename Type>
666 struct LogArgument;
667
668 template <>
669 struct LogArgument<WebCore::RTCStatsLogger> {
670     static String toString(const WebCore::RTCStatsLogger& logger)
671     {
672         return String(logger.toJSONString());
673     }
674 };
675
676 }; // namespace WTF
677
678
679 #endif // USE(LIBWEBRTC)