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