Remove unified plan runtime flag
[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 "JSDOMPromiseDeferred.h"
32 #include "JSRTCStatsReport.h"
33 #include "LibWebRTCDataChannelHandler.h"
34 #include "LibWebRTCPeerConnectionBackend.h"
35 #include "LibWebRTCProvider.h"
36 #include "LibWebRTCRtpReceiverBackend.h"
37 #include "LibWebRTCRtpSenderBackend.h"
38 #include "LibWebRTCRtpTransceiverBackend.h"
39 #include "LibWebRTCStatsCollector.h"
40 #include "LibWebRTCUtils.h"
41 #include "Logging.h"
42 #include "NotImplemented.h"
43 #include "Performance.h"
44 #include "PlatformStrategies.h"
45 #include "RTCDataChannel.h"
46 #include "RTCDataChannelEvent.h"
47 #include "RTCOfferOptions.h"
48 #include "RTCPeerConnection.h"
49 #include "RTCSessionDescription.h"
50 #include "RTCStatsReport.h"
51 #include "RealtimeIncomingAudioSource.h"
52 #include "RealtimeIncomingVideoSource.h"
53 #include "RealtimeOutgoingAudioSource.h"
54 #include "RealtimeOutgoingVideoSource.h"
55 #include "RuntimeEnabledFeatures.h"
56 #include <webrtc/rtc_base/physicalsocketserver.h>
57 #include <webrtc/p2p/base/basicpacketsocketfactory.h>
58 #include <webrtc/p2p/client/basicportallocator.h>
59 #include <webrtc/pc/peerconnectionfactory.h>
60 #include <webrtc/system_wrappers/include/field_trial.h>
61 #include <wtf/MainThread.h>
62
63 namespace WebCore {
64
65 LibWebRTCMediaEndpoint::LibWebRTCMediaEndpoint(LibWebRTCPeerConnectionBackend& peerConnection, LibWebRTCProvider& client)
66     : m_peerConnectionBackend(peerConnection)
67     , m_peerConnectionFactory(*client.factory())
68     , m_createSessionDescriptionObserver(*this)
69     , m_setLocalSessionDescriptionObserver(*this)
70     , m_setRemoteSessionDescriptionObserver(*this)
71     , m_statsLogTimer(*this, &LibWebRTCMediaEndpoint::gatherStatsForLogging)
72 #if !RELEASE_LOG_DISABLED
73     , m_logger(peerConnection.logger())
74     , m_logIdentifier(peerConnection.logIdentifier())
75 #endif
76 {
77     ASSERT(isMainThread());
78     ASSERT(client.factory());
79
80     if (RuntimeEnabledFeatures::sharedFeatures().webRTCH264SimulcastEnabled())
81         webrtc::field_trial::InitFieldTrialsFromString("WebRTC-H264Simulcast/Enabled/");
82 }
83
84 bool LibWebRTCMediaEndpoint::setConfiguration(LibWebRTCProvider& client, webrtc::PeerConnectionInterface::RTCConfiguration&& configuration)
85 {
86     configuration.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
87
88     if (!m_backend) {
89         if (!m_rtcSocketFactory) {
90             auto& document = downcast<Document>(*m_peerConnectionBackend.connection().scriptExecutionContext());
91             m_rtcSocketFactory = client.createSocketFactory(document.userAgent(document.url()));
92         }
93         m_backend = client.createPeerConnection(*this, m_rtcSocketFactory.get(), WTFMove(configuration));
94         return !!m_backend;
95     }
96     auto oldConfiguration = m_backend->GetConfiguration();
97     configuration.certificates = oldConfiguration.certificates;
98     return m_backend->SetConfiguration(WTFMove(configuration));
99 }
100
101 void LibWebRTCMediaEndpoint::suspend()
102 {
103     if (m_rtcSocketFactory)
104         m_rtcSocketFactory->suspend();
105 }
106
107 void LibWebRTCMediaEndpoint::resume()
108 {
109     if (m_rtcSocketFactory)
110         m_rtcSocketFactory->resume();
111 }
112
113 static inline const char* sessionDescriptionType(RTCSdpType sdpType)
114 {
115     switch (sdpType) {
116     case RTCSdpType::Offer:
117         return "offer";
118     case RTCSdpType::Pranswer:
119         return "pranswer";
120     case RTCSdpType::Answer:
121         return "answer";
122     case RTCSdpType::Rollback:
123         return "rollback";
124     }
125
126     ASSERT_NOT_REACHED();
127     return "";
128 }
129
130 static inline RTCSdpType fromSessionDescriptionType(const webrtc::SessionDescriptionInterface& description)
131 {
132     auto type = description.type();
133     if (type == webrtc::SessionDescriptionInterface::kOffer)
134         return RTCSdpType::Offer;
135     if (type == webrtc::SessionDescriptionInterface::kAnswer)
136         return RTCSdpType::Answer;
137     ASSERT(type == webrtc::SessionDescriptionInterface::kPrAnswer);
138     return RTCSdpType::Pranswer;
139 }
140
141 static inline RefPtr<RTCSessionDescription> fromSessionDescription(const webrtc::SessionDescriptionInterface* description)
142 {
143     if (!description)
144         return nullptr;
145
146     std::string sdp;
147     description->ToString(&sdp);
148
149     return RTCSessionDescription::create(fromSessionDescriptionType(*description), fromStdString(sdp));
150 }
151
152 // FIXME: We might want to create a new object only if the session actually changed for all description getters.
153 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::currentLocalDescription() const
154 {
155     return m_backend ? fromSessionDescription(m_backend->current_local_description()) : nullptr;
156 }
157
158 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::currentRemoteDescription() const
159 {
160     return m_backend ? fromSessionDescription(m_backend->current_remote_description()) : nullptr;
161 }
162
163 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::pendingLocalDescription() const
164 {
165     return m_backend ? fromSessionDescription(m_backend->pending_local_description()) : nullptr;
166 }
167
168 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::pendingRemoteDescription() const
169 {
170     return m_backend ? fromSessionDescription(m_backend->pending_remote_description()) : nullptr;
171 }
172
173 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::localDescription() const
174 {
175     return m_backend ? fromSessionDescription(m_backend->local_description()) : nullptr;
176 }
177
178 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::remoteDescription() const
179 {
180     return m_backend ? fromSessionDescription(m_backend->remote_description()) : nullptr;
181 }
182
183 void LibWebRTCMediaEndpoint::doSetLocalDescription(RTCSessionDescription& description)
184 {
185     ASSERT(m_backend);
186
187     webrtc::SdpParseError error;
188     std::unique_ptr<webrtc::SessionDescriptionInterface> sessionDescription(webrtc::CreateSessionDescription(sessionDescriptionType(description.type()), description.sdp().utf8().data(), &error));
189
190     if (!sessionDescription) {
191         m_peerConnectionBackend.setLocalDescriptionFailed(Exception { OperationError, fromStdString(error.description) });
192         return;
193     }
194
195     // FIXME: See https://bugs.webkit.org/show_bug.cgi?id=173783. Remove this test once fixed at LibWebRTC level.
196     if (description.type() == RTCSdpType::Answer && !m_backend->pending_remote_description()) {
197         m_peerConnectionBackend.setLocalDescriptionFailed(Exception { InvalidStateError, "Failed to set local answer sdp: no pending remote description."_s });
198         return;
199     }
200
201     m_backend->SetLocalDescription(&m_setLocalSessionDescriptionObserver, sessionDescription.release());
202 }
203
204 void LibWebRTCMediaEndpoint::doSetRemoteDescription(RTCSessionDescription& description)
205 {
206     ASSERT(m_backend);
207
208     webrtc::SdpParseError error;
209     std::unique_ptr<webrtc::SessionDescriptionInterface> sessionDescription(webrtc::CreateSessionDescription(sessionDescriptionType(description.type()), description.sdp().utf8().data(), &error));
210     if (!sessionDescription) {
211         m_peerConnectionBackend.setRemoteDescriptionFailed(Exception { SyntaxError, fromStdString(error.description) });
212         return;
213     }
214     m_backend->SetRemoteDescription(&m_setRemoteSessionDescriptionObserver, sessionDescription.release());
215
216     startLoggingStats();
217 }
218
219 bool LibWebRTCMediaEndpoint::addTrack(LibWebRTCRtpSenderBackend& sender, MediaStreamTrack& track, const Vector<String>& mediaStreamIds)
220 {
221     ASSERT(m_backend);
222
223     LibWebRTCRtpSenderBackend::Source source;
224     rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> rtcTrack;
225     switch (track.privateTrack().type()) {
226     case RealtimeMediaSource::Type::Audio: {
227         auto audioSource = RealtimeOutgoingAudioSource::create(track.privateTrack());
228         rtcTrack = m_peerConnectionFactory.CreateAudioTrack(track.id().utf8().data(), audioSource.ptr());
229         source = WTFMove(audioSource);
230         break;
231     }
232     case RealtimeMediaSource::Type::Video: {
233         auto videoSource = RealtimeOutgoingVideoSource::create(track.privateTrack());
234         rtcTrack = m_peerConnectionFactory.CreateVideoTrack(track.id().utf8().data(), videoSource.ptr());
235         source = WTFMove(videoSource);
236         break;
237     }
238     case RealtimeMediaSource::Type::None:
239         ASSERT_NOT_REACHED();
240         return false;
241     }
242
243     sender.setSource(WTFMove(source));
244     if (auto rtpSender = sender.rtcSender()) {
245         rtpSender->SetTrack(rtcTrack.get());
246         return true;
247     }
248
249     std::vector<std::string> ids;
250     for (auto& id : mediaStreamIds)
251         ids.push_back(id.utf8().data());
252
253     auto newRTPSender = m_backend->AddTrack(rtcTrack.get(), WTFMove(ids));
254     if (!newRTPSender.ok())
255         return false;
256     sender.setRTCSender(newRTPSender.MoveValue());
257     return true;
258 }
259
260 void LibWebRTCMediaEndpoint::removeTrack(LibWebRTCRtpSenderBackend& sender)
261 {
262     ASSERT(m_backend);
263     m_backend->RemoveTrack(sender.rtcSender());
264     sender.clearSource();
265 }
266
267 void LibWebRTCMediaEndpoint::doCreateOffer(const RTCOfferOptions& options)
268 {
269     ASSERT(m_backend);
270
271     m_isInitiator = true;
272     webrtc::PeerConnectionInterface::RTCOfferAnswerOptions rtcOptions;
273     rtcOptions.ice_restart = options.iceRestart;
274     rtcOptions.voice_activity_detection = options.voiceActivityDetection;
275
276     m_backend->CreateOffer(&m_createSessionDescriptionObserver, rtcOptions);
277 }
278
279 void LibWebRTCMediaEndpoint::doCreateAnswer()
280 {
281     ASSERT(m_backend);
282
283     m_isInitiator = false;
284     m_backend->CreateAnswer(&m_createSessionDescriptionObserver, { });
285 }
286
287 rtc::scoped_refptr<LibWebRTCStatsCollector> LibWebRTCMediaEndpoint::createStatsCollector(Ref<DeferredPromise>&& promise)
288 {
289     return LibWebRTCStatsCollector::create([promise = WTFMove(promise), protectedThis = makeRef(*this)]() mutable -> RefPtr<RTCStatsReport> {
290         ASSERT(isMainThread());
291         if (protectedThis->isStopped())
292             return nullptr;
293
294         auto report = RTCStatsReport::create();
295
296         promise->resolve<IDLInterface<RTCStatsReport>>(report.copyRef());
297
298         // The promise resolution might fail in which case no backing map will be created.
299         if (!report->backingMap())
300             return nullptr;
301         return report;
302     });
303 }
304
305 void LibWebRTCMediaEndpoint::getStats(Ref<DeferredPromise>&& promise)
306 {
307     if (m_backend)
308         m_backend->GetStats(createStatsCollector(WTFMove(promise)));
309 }
310
311 void LibWebRTCMediaEndpoint::getStats(webrtc::RtpReceiverInterface& receiver, Ref<DeferredPromise>&& promise)
312 {
313     if (m_backend)
314         m_backend->GetStats(rtc::scoped_refptr<webrtc::RtpReceiverInterface>(&receiver), createStatsCollector(WTFMove(promise)));
315 }
316
317 void LibWebRTCMediaEndpoint::getStats(webrtc::RtpSenderInterface& sender, Ref<DeferredPromise>&& promise)
318 {
319     if (m_backend)
320         m_backend->GetStats(rtc::scoped_refptr<webrtc::RtpSenderInterface>(&sender), createStatsCollector(WTFMove(promise)));
321 }
322
323 static RTCSignalingState signalingState(webrtc::PeerConnectionInterface::SignalingState state)
324 {
325     switch (state) {
326     case webrtc::PeerConnectionInterface::kStable:
327         return RTCSignalingState::Stable;
328     case webrtc::PeerConnectionInterface::kHaveLocalOffer:
329         return RTCSignalingState::HaveLocalOffer;
330     case webrtc::PeerConnectionInterface::kHaveLocalPrAnswer:
331         return RTCSignalingState::HaveLocalPranswer;
332     case webrtc::PeerConnectionInterface::kHaveRemoteOffer:
333         return RTCSignalingState::HaveRemoteOffer;
334     case webrtc::PeerConnectionInterface::kHaveRemotePrAnswer:
335         return RTCSignalingState::HaveRemotePranswer;
336     case webrtc::PeerConnectionInterface::kClosed:
337         return RTCSignalingState::Stable;
338     }
339
340     ASSERT_NOT_REACHED();
341     return RTCSignalingState::Stable;
342 }
343
344 void LibWebRTCMediaEndpoint::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState rtcState)
345 {
346     auto state = signalingState(rtcState);
347     callOnMainThread([protectedThis = makeRef(*this), state] {
348         if (protectedThis->isStopped())
349             return;
350         protectedThis->m_peerConnectionBackend.updateSignalingState(state);
351     });
352 }
353
354 MediaStream& LibWebRTCMediaEndpoint::mediaStreamFromRTCStream(webrtc::MediaStreamInterface& rtcStream)
355 {
356     auto label = fromStdString(rtcStream.id());
357     auto mediaStream = m_remoteStreamsById.ensure(label, [label, this]() mutable {
358         auto& document = downcast<Document>(*m_peerConnectionBackend.connection().scriptExecutionContext());
359         return MediaStream::create(document, MediaStreamPrivate::create(document.logger(), { }, WTFMove(label)));
360     });
361     return *mediaStream.iterator->value;
362 }
363
364 void LibWebRTCMediaEndpoint::addRemoteStream(webrtc::MediaStreamInterface&)
365 {
366 }
367
368 void LibWebRTCMediaEndpoint::addRemoteTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface>&& rtcReceiver, const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& rtcStreams)
369 {
370     ASSERT(rtcReceiver);
371     RefPtr<RTCRtpReceiver> receiver;
372     RefPtr<RealtimeMediaSource> remoteSource;
373
374     auto* rtcTrack = rtcReceiver->track().get();
375
376     switch (rtcReceiver->media_type()) {
377     case cricket::MEDIA_TYPE_DATA:
378         return;
379     case cricket::MEDIA_TYPE_AUDIO: {
380         rtc::scoped_refptr<webrtc::AudioTrackInterface> audioTrack = static_cast<webrtc::AudioTrackInterface*>(rtcTrack);
381         auto audioReceiver = m_peerConnectionBackend.audioReceiver(fromStdString(rtcTrack->id()));
382
383         receiver = WTFMove(audioReceiver.receiver);
384         audioReceiver.source->setSourceTrack(WTFMove(audioTrack));
385         break;
386     }
387     case cricket::MEDIA_TYPE_VIDEO: {
388         rtc::scoped_refptr<webrtc::VideoTrackInterface> videoTrack = static_cast<webrtc::VideoTrackInterface*>(rtcTrack);
389         auto videoReceiver = m_peerConnectionBackend.videoReceiver(fromStdString(rtcTrack->id()));
390
391         receiver = WTFMove(videoReceiver.receiver);
392         videoReceiver.source->setSourceTrack(WTFMove(videoTrack));
393         break;
394     }
395     }
396
397     receiver->setBackend(makeUnique<LibWebRTCRtpReceiverBackend>(WTFMove(rtcReceiver)));
398     auto& track = receiver->track();
399     addPendingTrackEvent(receiver.releaseNonNull(), track, rtcStreams, nullptr);
400 }
401
402 void LibWebRTCMediaEndpoint::addPendingTrackEvent(Ref<RTCRtpReceiver>&& receiver, MediaStreamTrack& track, const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& rtcStreams, RefPtr<RTCRtpTransceiver>&& transceiver)
403 {
404     Vector<RefPtr<MediaStream>> streams;
405     for (auto& rtcStream : rtcStreams) {
406         auto& mediaStream = mediaStreamFromRTCStream(*rtcStream.get());
407         streams.append(&mediaStream);
408         mediaStream.addTrackFromPlatform(track);
409     }
410     auto streamIds = WTF::map(streams, [](auto& stream) -> String {
411         return stream->id();
412     });
413     m_remoteStreamsFromRemoteTrack.add(&track, WTFMove(streamIds));
414
415     m_peerConnectionBackend.addPendingTrackEvent({ WTFMove(receiver), makeRef(track), WTFMove(streams), WTFMove(transceiver) });
416 }
417
418 static inline void setExistingReceiverSourceTrack(RealtimeMediaSource& existingSource, webrtc::RtpReceiverInterface& rtcReceiver)
419 {
420     switch (rtcReceiver.media_type()) {
421     case cricket::MEDIA_TYPE_AUDIO: {
422         ASSERT(existingSource.type() == RealtimeMediaSource::Type::Audio);
423         rtc::scoped_refptr<webrtc::AudioTrackInterface> audioTrack = static_cast<webrtc::AudioTrackInterface*>(rtcReceiver.track().get());
424         downcast<RealtimeIncomingAudioSource>(existingSource).setSourceTrack(WTFMove(audioTrack));
425         return;
426     }
427     case cricket::MEDIA_TYPE_VIDEO: {
428         ASSERT(existingSource.type() == RealtimeMediaSource::Type::Video);
429         rtc::scoped_refptr<webrtc::VideoTrackInterface> videoTrack = static_cast<webrtc::VideoTrackInterface*>(rtcReceiver.track().get());
430         downcast<RealtimeIncomingVideoSource>(existingSource).setSourceTrack(WTFMove(videoTrack));
431         return;
432     }
433     case cricket::MEDIA_TYPE_DATA:
434         ASSERT_NOT_REACHED();
435         return;
436     }
437 }
438
439 RefPtr<RealtimeMediaSource> LibWebRTCMediaEndpoint::sourceFromNewReceiver(webrtc::RtpReceiverInterface& rtcReceiver)
440 {
441     auto rtcTrack = rtcReceiver.track();
442     switch (rtcReceiver.media_type()) {
443     case cricket::MEDIA_TYPE_DATA:
444         return nullptr;
445     case cricket::MEDIA_TYPE_AUDIO: {
446         rtc::scoped_refptr<webrtc::AudioTrackInterface> audioTrack = static_cast<webrtc::AudioTrackInterface*>(rtcTrack.get());
447         return RealtimeIncomingAudioSource::create(WTFMove(audioTrack), fromStdString(rtcTrack->id()));
448     }
449     case cricket::MEDIA_TYPE_VIDEO: {
450         rtc::scoped_refptr<webrtc::VideoTrackInterface> videoTrack = static_cast<webrtc::VideoTrackInterface*>(rtcTrack.get());
451         return RealtimeIncomingVideoSource::create(WTFMove(videoTrack), fromStdString(rtcTrack->id()));
452     }
453     }
454
455     RELEASE_ASSERT_NOT_REACHED();
456 }
457
458 void LibWebRTCMediaEndpoint::collectTransceivers()
459 {
460     if (!m_backend)
461         return;
462
463     for (auto& rtcTransceiver : m_backend->GetTransceivers()) {
464         auto* existingTransceiver = m_peerConnectionBackend.existingTransceiver([&](auto& transceiverBackend) {
465             return rtcTransceiver.get() == transceiverBackend.rtcTransceiver();
466         });
467         if (existingTransceiver)
468             continue;
469
470         auto rtcReceiver = rtcTransceiver->receiver();
471         auto source = sourceFromNewReceiver(*rtcReceiver);
472         if (!source)
473             return;
474
475         m_peerConnectionBackend.newRemoteTransceiver(makeUnique<LibWebRTCRtpTransceiverBackend>(WTFMove(rtcTransceiver)), source.releaseNonNull());
476     }
477 }
478
479 void LibWebRTCMediaEndpoint::newTransceiver(rtc::scoped_refptr<webrtc::RtpTransceiverInterface>&& rtcTransceiver)
480 {
481     auto* transceiver = m_peerConnectionBackend.existingTransceiver([&](auto& transceiverBackend) {
482         return rtcTransceiver.get() == transceiverBackend.rtcTransceiver();
483     });
484     if (transceiver) {
485         auto rtcReceiver = rtcTransceiver->receiver();
486         setExistingReceiverSourceTrack(transceiver->receiver().track().source(), *rtcReceiver);
487         addPendingTrackEvent(makeRef(transceiver->receiver()), transceiver->receiver().track(), rtcReceiver->streams(), makeRef(*transceiver));
488         return;
489     }
490
491     auto rtcReceiver = rtcTransceiver->receiver();
492     auto source = sourceFromNewReceiver(*rtcReceiver);
493     if (!source)
494         return;
495
496     auto& newTransceiver = m_peerConnectionBackend.newRemoteTransceiver(makeUnique<LibWebRTCRtpTransceiverBackend>(WTFMove(rtcTransceiver)), source.releaseNonNull());
497
498     addPendingTrackEvent(makeRef(newTransceiver.receiver()), newTransceiver.receiver().track(), rtcReceiver->streams(), makeRef(newTransceiver));
499 }
500
501 void LibWebRTCMediaEndpoint::removeRemoteTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface>&& receiver)
502 {
503     auto* transceiver = m_peerConnectionBackend.existingTransceiver([&receiver](auto& transceiverBackend) {
504         auto* rtcTransceiver = transceiverBackend.rtcTransceiver();
505         return rtcTransceiver && receiver.get() == rtcTransceiver->receiver().get();
506     });
507     if (!transceiver)
508         return;
509
510     auto& track = transceiver->receiver().track();
511
512     for (auto& id : m_remoteStreamsFromRemoteTrack.get(&track)) {
513         if (auto stream = m_remoteStreamsById.get(id))
514             stream->privateStream().removeTrack(track.privateTrack(), MediaStreamPrivate::NotifyClientOption::Notify);
515     }
516
517     track.source().setMuted(true);
518 }
519
520 template<typename T>
521 Optional<LibWebRTCMediaEndpoint::Backends> LibWebRTCMediaEndpoint::createTransceiverBackends(T&& trackOrKind, const RTCRtpTransceiverInit& init, LibWebRTCRtpSenderBackend::Source&& source)
522 {
523     auto result = m_backend->AddTransceiver(WTFMove(trackOrKind), fromRtpTransceiverInit(init));
524     if (!result.ok())
525         return WTF::nullopt;
526
527     auto transceiver = makeUnique<LibWebRTCRtpTransceiverBackend>(result.MoveValue());
528     return LibWebRTCMediaEndpoint::Backends { transceiver->createSenderBackend(m_peerConnectionBackend, WTFMove(source)), transceiver->createReceiverBackend(), WTFMove(transceiver) };
529 }
530
531 Optional<LibWebRTCMediaEndpoint::Backends> LibWebRTCMediaEndpoint::addTransceiver(const String& trackKind, const RTCRtpTransceiverInit& init)
532 {
533     auto type = trackKind == "audio" ? cricket::MediaType::MEDIA_TYPE_AUDIO : cricket::MediaType::MEDIA_TYPE_VIDEO;
534     return createTransceiverBackends(type, init, nullptr);
535 }
536
537 std::pair<LibWebRTCRtpSenderBackend::Source, rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>> LibWebRTCMediaEndpoint::createSourceAndRTCTrack(MediaStreamTrack& track)
538 {
539     LibWebRTCRtpSenderBackend::Source source;
540     rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> rtcTrack;
541     switch (track.privateTrack().type()) {
542     case RealtimeMediaSource::Type::None:
543         ASSERT_NOT_REACHED();
544         break;
545     case RealtimeMediaSource::Type::Audio: {
546         auto audioSource = RealtimeOutgoingAudioSource::create(track.privateTrack());
547         rtcTrack = m_peerConnectionFactory.CreateAudioTrack(track.id().utf8().data(), audioSource.ptr());
548         source = WTFMove(audioSource);
549         break;
550     }
551     case RealtimeMediaSource::Type::Video: {
552         auto videoSource = RealtimeOutgoingVideoSource::create(track.privateTrack());
553         rtcTrack = m_peerConnectionFactory.CreateVideoTrack(track.id().utf8().data(), videoSource.ptr());
554         source = WTFMove(videoSource);
555         break;
556     }
557     }
558     return std::make_pair(WTFMove(source), WTFMove(rtcTrack));
559 }
560
561 Optional<LibWebRTCMediaEndpoint::Backends> LibWebRTCMediaEndpoint::addTransceiver(MediaStreamTrack& track, const RTCRtpTransceiverInit& init)
562 {
563     auto sourceAndTrack = createSourceAndRTCTrack(track);
564     return createTransceiverBackends(WTFMove(sourceAndTrack.second), init, WTFMove(sourceAndTrack.first));
565 }
566
567 void LibWebRTCMediaEndpoint::setSenderSourceFromTrack(LibWebRTCRtpSenderBackend& sender, MediaStreamTrack& track)
568 {
569     auto sourceAndTrack = createSourceAndRTCTrack(track);
570     sender.setSource(WTFMove(sourceAndTrack.first));
571     sender.rtcSender()->SetTrack(WTFMove(sourceAndTrack.second));
572 }
573
574 std::unique_ptr<LibWebRTCRtpTransceiverBackend> LibWebRTCMediaEndpoint::transceiverBackendFromSender(LibWebRTCRtpSenderBackend& backend)
575 {
576     for (auto& transceiver : m_backend->GetTransceivers()) {
577         if (transceiver->sender().get() == backend.rtcSender())
578             return makeUnique<LibWebRTCRtpTransceiverBackend>(rtc::scoped_refptr<webrtc::RtpTransceiverInterface>(transceiver));
579     }
580     return nullptr;
581 }
582
583
584 void LibWebRTCMediaEndpoint::removeRemoteStream(webrtc::MediaStreamInterface& rtcStream)
585 {
586     bool removed = m_remoteStreamsById.remove(fromStdString(rtcStream.id()));
587     ASSERT_UNUSED(removed, removed);
588 }
589
590 void LibWebRTCMediaEndpoint::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)
591 {
592     callOnMainThread([protectedThis = makeRef(*this), stream = WTFMove(stream)] {
593         if (protectedThis->isStopped())
594             return;
595         ASSERT(stream);
596         protectedThis->addRemoteStream(*stream.get());
597     });
598 }
599
600 void LibWebRTCMediaEndpoint::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)
601 {
602     callOnMainThread([protectedThis = makeRef(*this), stream = WTFMove(stream)] {
603         if (protectedThis->isStopped())
604             return;
605         ASSERT(stream);
606         protectedThis->removeRemoteStream(*stream.get());
607     });
608 }
609
610 void LibWebRTCMediaEndpoint::OnTrack(rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver)
611 {
612     callOnMainThread([protectedThis = makeRef(*this), transceiver = WTFMove(transceiver)]() mutable {
613         if (protectedThis->isStopped())
614             return;
615         protectedThis->newTransceiver(WTFMove(transceiver));
616     });
617 }
618
619 void LibWebRTCMediaEndpoint::OnRemoveTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver)
620 {
621     callOnMainThread([protectedThis = makeRef(*this), receiver = WTFMove(receiver)]() mutable {
622         if (protectedThis->isStopped())
623             return;
624         protectedThis->removeRemoteTrack(WTFMove(receiver));
625     });
626 }
627
628 std::unique_ptr<RTCDataChannelHandler> LibWebRTCMediaEndpoint::createDataChannel(const String& label, const RTCDataChannelInit& options)
629 {
630     auto init = LibWebRTCDataChannelHandler::fromRTCDataChannelInit(options);
631     auto channel = m_backend->CreateDataChannel(label.utf8().data(), &init);
632     return channel ? makeUnique<LibWebRTCDataChannelHandler>(WTFMove(channel)) : nullptr;
633 }
634
635 void LibWebRTCMediaEndpoint::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel)
636 {
637     callOnMainThread([protectedThis = makeRef(*this), dataChannel = WTFMove(dataChannel)]() mutable {
638         if (protectedThis->isStopped())
639             return;
640         auto& connection = protectedThis->m_peerConnectionBackend.connection();
641         connection.dispatchEventWhenFeasible(LibWebRTCDataChannelHandler::channelEvent(*connection.document(), WTFMove(dataChannel)));
642     });
643 }
644
645 void LibWebRTCMediaEndpoint::stop()
646 {
647     if (!m_backend)
648         return;
649
650     stopLoggingStats();
651
652     m_backend->Close();
653     m_backend = nullptr;
654     m_remoteStreamsById.clear();
655     m_remoteStreamsFromRemoteTrack.clear();
656 }
657
658 void LibWebRTCMediaEndpoint::OnRenegotiationNeeded()
659 {
660     callOnMainThread([protectedThis = makeRef(*this)] {
661         if (protectedThis->isStopped())
662             return;
663         protectedThis->m_peerConnectionBackend.markAsNeedingNegotiation();
664     });
665 }
666
667 static inline RTCIceConnectionState toRTCIceConnectionState(webrtc::PeerConnectionInterface::IceConnectionState state)
668 {
669     switch (state) {
670     case webrtc::PeerConnectionInterface::kIceConnectionNew:
671         return RTCIceConnectionState::New;
672     case webrtc::PeerConnectionInterface::kIceConnectionChecking:
673         return RTCIceConnectionState::Checking;
674     case webrtc::PeerConnectionInterface::kIceConnectionConnected:
675         return RTCIceConnectionState::Connected;
676     case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
677         return RTCIceConnectionState::Completed;
678     case webrtc::PeerConnectionInterface::kIceConnectionFailed:
679         return RTCIceConnectionState::Failed;
680     case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
681         return RTCIceConnectionState::Disconnected;
682     case webrtc::PeerConnectionInterface::kIceConnectionClosed:
683         return RTCIceConnectionState::Closed;
684     case webrtc::PeerConnectionInterface::kIceConnectionMax:
685         break;
686     }
687
688     ASSERT_NOT_REACHED();
689     return RTCIceConnectionState::New;
690 }
691
692 void LibWebRTCMediaEndpoint::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState state)
693 {
694     auto connectionState = toRTCIceConnectionState(state);
695     callOnMainThread([protectedThis = makeRef(*this), connectionState] {
696         if (protectedThis->isStopped())
697             return;
698         if (protectedThis->m_peerConnectionBackend.connection().iceConnectionState() != connectionState)
699             protectedThis->m_peerConnectionBackend.connection().updateIceConnectionState(connectionState);
700     });
701 }
702
703 void LibWebRTCMediaEndpoint::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState state)
704 {
705     callOnMainThread([protectedThis = makeRef(*this), state] {
706         if (protectedThis->isStopped())
707             return;
708         if (state == webrtc::PeerConnectionInterface::kIceGatheringComplete)
709             protectedThis->m_peerConnectionBackend.doneGatheringCandidates();
710         else if (state == webrtc::PeerConnectionInterface::kIceGatheringGathering)
711             protectedThis->m_peerConnectionBackend.connection().updateIceGatheringState(RTCIceGatheringState::Gathering);
712     });
713 }
714
715 void LibWebRTCMediaEndpoint::OnIceCandidate(const webrtc::IceCandidateInterface *rtcCandidate)
716 {
717     ASSERT(rtcCandidate);
718
719     std::string sdp;
720     rtcCandidate->ToString(&sdp);
721
722     auto sdpMLineIndex = safeCast<unsigned short>(rtcCandidate->sdp_mline_index());
723
724     callOnMainThread([protectedThis = makeRef(*this), mid = fromStdString(rtcCandidate->sdp_mid()), sdp = fromStdString(sdp), sdpMLineIndex, url = fromStdString(rtcCandidate->server_url())]() mutable {
725         if (protectedThis->isStopped())
726             return;
727         protectedThis->m_peerConnectionBackend.newICECandidate(WTFMove(sdp), WTFMove(mid), sdpMLineIndex, WTFMove(url));
728     });
729 }
730
731 void LibWebRTCMediaEndpoint::OnIceCandidatesRemoved(const std::vector<cricket::Candidate>&)
732 {
733     ASSERT_NOT_REACHED();
734 }
735
736 void LibWebRTCMediaEndpoint::createSessionDescriptionSucceeded(std::unique_ptr<webrtc::SessionDescriptionInterface>&& description)
737 {
738     std::string sdp;
739     description->ToString(&sdp);
740
741     callOnMainThread([protectedThis = makeRef(*this), sdp = fromStdString(sdp)]() mutable {
742         if (protectedThis->isStopped())
743             return;
744         if (protectedThis->m_isInitiator)
745             protectedThis->m_peerConnectionBackend.createOfferSucceeded(WTFMove(sdp));
746         else
747             protectedThis->m_peerConnectionBackend.createAnswerSucceeded(WTFMove(sdp));
748     });
749 }
750
751 void LibWebRTCMediaEndpoint::createSessionDescriptionFailed(ExceptionCode errorCode, const char* errorMessage)
752 {
753     callOnMainThread([protectedThis = makeRef(*this), errorCode, errorMessage = String(errorMessage)] () mutable {
754         if (protectedThis->isStopped())
755             return;
756         if (protectedThis->m_isInitiator)
757             protectedThis->m_peerConnectionBackend.createOfferFailed(Exception { errorCode, WTFMove(errorMessage) });
758         else
759             protectedThis->m_peerConnectionBackend.createAnswerFailed(Exception { errorCode, WTFMove(errorMessage) });
760     });
761 }
762
763 void LibWebRTCMediaEndpoint::setLocalSessionDescriptionSucceeded()
764 {
765     callOnMainThread([protectedThis = makeRef(*this)] {
766         if (protectedThis->isStopped())
767             return;
768         protectedThis->m_peerConnectionBackend.setLocalDescriptionSucceeded();
769     });
770 }
771
772 void LibWebRTCMediaEndpoint::setLocalSessionDescriptionFailed(ExceptionCode errorCode, const char* errorMessage)
773 {
774     callOnMainThread([protectedThis = makeRef(*this), errorCode, errorMessage = String(errorMessage)] () mutable {
775         if (protectedThis->isStopped())
776             return;
777         protectedThis->m_peerConnectionBackend.setLocalDescriptionFailed(Exception { errorCode, WTFMove(errorMessage) });
778     });
779 }
780
781 void LibWebRTCMediaEndpoint::setRemoteSessionDescriptionSucceeded()
782 {
783     callOnMainThread([protectedThis = makeRef(*this)] {
784         if (protectedThis->isStopped())
785             return;
786         protectedThis->m_peerConnectionBackend.setRemoteDescriptionSucceeded();
787     });
788 }
789
790 void LibWebRTCMediaEndpoint::setRemoteSessionDescriptionFailed(ExceptionCode errorCode, const char* errorMessage)
791 {
792     callOnMainThread([protectedThis = makeRef(*this), errorCode, errorMessage = String(errorMessage)] () mutable {
793         if (protectedThis->isStopped())
794             return;
795         protectedThis->m_peerConnectionBackend.setRemoteDescriptionFailed(Exception { errorCode, WTFMove(errorMessage) });
796     });
797 }
798
799 void LibWebRTCMediaEndpoint::gatherStatsForLogging()
800 {
801     m_backend->GetStats(this);
802 }
803
804 class RTCStatsLogger {
805 public:
806     explicit RTCStatsLogger(const webrtc::RTCStats& stats)
807         : m_stats(stats)
808     {
809     }
810
811     String toJSONString() const { return String(m_stats.ToJson().c_str()); }
812
813 private:
814     const webrtc::RTCStats& m_stats;
815 };
816
817 void LibWebRTCMediaEndpoint::OnStatsDelivered(const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report)
818 {
819 #if !RELEASE_LOG_DISABLED
820     int64_t timestamp = report->timestamp_us();
821     if (!m_statsFirstDeliveredTimestamp)
822         m_statsFirstDeliveredTimestamp = timestamp;
823
824     callOnMainThread([protectedThis = makeRef(*this), this, timestamp, report] {
825         if (m_backend && m_statsLogTimer.repeatInterval() != statsLogInterval(timestamp)) {
826             m_statsLogTimer.stop();
827             m_statsLogTimer.startRepeating(statsLogInterval(timestamp));
828         }
829
830         for (auto iterator = report->begin(); iterator != report->end(); ++iterator) {
831             if (logger().willLog(logChannel(), WTFLogLevel::Debug)) {
832                 // Stats are very verbose, let's only display them in inspector console in verbose mode.
833                 logger().debug(LogWebRTC,
834                     Logger::LogSiteIdentifier("LibWebRTCMediaEndpoint", "OnStatsDelivered", logIdentifier()),
835                     RTCStatsLogger { *iterator });
836             } else {
837                 logger().logAlways(LogWebRTCStats,
838                     Logger::LogSiteIdentifier("LibWebRTCMediaEndpoint", "OnStatsDelivered", logIdentifier()),
839                     RTCStatsLogger { *iterator });
840             }
841         }
842     });
843 #else
844     UNUSED_PARAM(report);
845 #endif
846 }
847
848 void LibWebRTCMediaEndpoint::startLoggingStats()
849 {
850 #if !RELEASE_LOG_DISABLED
851     if (m_statsLogTimer.isActive())
852         m_statsLogTimer.stop();
853     m_statsLogTimer.startRepeating(statsLogInterval(0));
854 #endif
855 }
856
857 void LibWebRTCMediaEndpoint::stopLoggingStats()
858 {
859     m_statsLogTimer.stop();
860 }
861
862 #if !RELEASE_LOG_DISABLED
863 WTFLogChannel& LibWebRTCMediaEndpoint::logChannel() const
864 {
865     return LogWebRTC;
866 }
867
868 Seconds LibWebRTCMediaEndpoint::statsLogInterval(int64_t reportTimestamp) const
869 {
870     if (logger().willLog(logChannel(), WTFLogLevel::Info))
871         return 2_s;
872
873     if (reportTimestamp - m_statsFirstDeliveredTimestamp > 15000000)
874         return 10_s;
875
876     return 4_s;
877 }
878 #endif
879
880 } // namespace WebCore
881
882 namespace WTF {
883
884 template<typename Type>
885 struct LogArgument;
886
887 template <>
888 struct LogArgument<WebCore::RTCStatsLogger> {
889     static String toString(const WebCore::RTCStatsLogger& logger)
890     {
891         return String(logger.toJSONString());
892     }
893 };
894
895 }; // namespace WTF
896
897
898 #endif // USE(LIBWEBRTC)