26a5fa9c13b49826272527a9f0d3ffc7e2803a21
[WebKit-https.git] / Source / WebCore / Modules / mediastream / libwebrtc / LibWebRTCMediaEndpoint.cpp
1 /*
2  * Copyright (C) 2017 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 "JSDOMConvert.h"
32 #include "JSRTCStatsReport.h"
33 #include "LibWebRTCDataChannelHandler.h"
34 #include "LibWebRTCPeerConnectionBackend.h"
35 #include "LibWebRTCProvider.h"
36 #include "MediaStreamEvent.h"
37 #include "NotImplemented.h"
38 #include "PlatformStrategies.h"
39 #include "RTCDataChannel.h"
40 #include "RTCDataChannelEvent.h"
41 #include "RTCEnums.h"
42 #include "RTCPeerConnection.h"
43 #include "RTCSessionDescription.h"
44 #include "RTCStatsReport.h"
45 #include "RTCTrackEvent.h"
46 #include "RealtimeIncomingAudioSource.h"
47 #include "RealtimeIncomingVideoSource.h"
48 #include <webrtc/base/physicalsocketserver.h>
49 #include <webrtc/p2p/base/basicpacketsocketfactory.h>
50 #include <webrtc/p2p/client/basicportallocator.h>
51 #include <webrtc/pc/peerconnectionfactory.h>
52 #include <wtf/MainThread.h>
53
54 #include "CoreMediaSoftLink.h"
55
56 namespace WebCore {
57
58 LibWebRTCMediaEndpoint::LibWebRTCMediaEndpoint(LibWebRTCPeerConnectionBackend& peerConnection, LibWebRTCProvider& client)
59     : m_peerConnectionBackend(peerConnection)
60     , m_backend(client.createPeerConnection(*this))
61     , m_createSessionDescriptionObserver(*this)
62     , m_setLocalSessionDescriptionObserver(*this)
63     , m_setRemoteSessionDescriptionObserver(*this)
64 {
65     ASSERT(m_backend);
66 }
67
68 static inline const char* sessionDescriptionType(RTCSessionDescription::SdpType sdpType)
69 {
70     switch (sdpType) {
71     case RTCSessionDescription::SdpType::Offer:
72         return "offer";
73     case RTCSessionDescription::SdpType::Pranswer:
74         return "pranswer";
75     case RTCSessionDescription::SdpType::Answer:
76         return "answer";
77     case RTCSessionDescription::SdpType::Rollback:
78         return "rollback";
79     }
80 }
81
82 static inline RTCSessionDescription::SdpType fromSessionDescriptionType(const webrtc::SessionDescriptionInterface& description)
83 {
84     auto type = description.type();
85     if (type == webrtc::SessionDescriptionInterface::kOffer)
86         return RTCSessionDescription::SdpType::Offer;
87     if (type == webrtc::SessionDescriptionInterface::kAnswer)
88         return RTCSessionDescription::SdpType::Answer;
89     ASSERT(type == webrtc::SessionDescriptionInterface::kPrAnswer);
90     return RTCSessionDescription::SdpType::Pranswer;
91 }
92
93 static inline RefPtr<RTCSessionDescription> fromSessionDescription(const webrtc::SessionDescriptionInterface* description)
94 {
95     if (!description)
96         return nullptr;
97
98     std::string sdp;
99     description->ToString(&sdp);
100     String sdpString(sdp.data(), sdp.size());
101
102     return RTCSessionDescription::create(fromSessionDescriptionType(*description), WTFMove(sdpString));
103 }
104
105 // FIXME: We might want to create a new object only if the session actually changed for all description getters.
106 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::currentLocalDescription() const
107 {
108     return fromSessionDescription(m_backend->current_local_description());
109 }
110
111 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::currentRemoteDescription() const
112 {
113     return fromSessionDescription(m_backend->current_remote_description());
114 }
115
116 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::pendingLocalDescription() const
117 {
118     return fromSessionDescription(m_backend->pending_local_description());
119 }
120
121 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::pendingRemoteDescription() const
122 {
123     return fromSessionDescription(m_backend->pending_remote_description());
124 }
125
126 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::localDescription() const
127 {
128     return fromSessionDescription(m_backend->local_description());
129 }
130
131 RefPtr<RTCSessionDescription> LibWebRTCMediaEndpoint::remoteDescription() const
132 {
133     // FIXME: We might want to create a new object only if the session actually changed.
134     return fromSessionDescription(m_backend->remote_description());
135 }
136
137 void LibWebRTCMediaEndpoint::doSetLocalDescription(RTCSessionDescription& description)
138 {
139     webrtc::SdpParseError error;
140     std::unique_ptr<webrtc::SessionDescriptionInterface> sessionDescription(webrtc::CreateSessionDescription(sessionDescriptionType(description.type()), description.sdp().utf8().data(), &error));
141
142     if (!sessionDescription) {
143         String errorMessage(error.description.data(), error.description.size());
144         m_peerConnectionBackend.setLocalDescriptionFailed(Exception { OperationError, WTFMove(errorMessage) });
145         return;
146     }
147     m_backend->SetLocalDescription(&m_setLocalSessionDescriptionObserver, sessionDescription.release());
148 }
149
150 void LibWebRTCMediaEndpoint::doSetRemoteDescription(RTCSessionDescription& description)
151 {
152     webrtc::SdpParseError error;
153     std::unique_ptr<webrtc::SessionDescriptionInterface> sessionDescription(webrtc::CreateSessionDescription(sessionDescriptionType(description.type()), description.sdp().utf8().data(), &error));
154     if (!sessionDescription) {
155         String errorMessage(error.description.data(), error.description.size());
156         m_peerConnectionBackend.setRemoteDescriptionFailed(Exception { OperationError, WTFMove(errorMessage) });
157         return;
158     }
159     m_backend->SetRemoteDescription(&m_setRemoteSessionDescriptionObserver, sessionDescription.release());
160 }
161
162 void LibWebRTCMediaEndpoint::addTrack(MediaStreamTrack& track, const Vector<String>& mediaStreamIds)
163 {
164     if (!LibWebRTCProvider::factory())
165         return;
166
167     std::vector<webrtc::MediaStreamInterface*> mediaStreams;
168     rtc::scoped_refptr<webrtc::MediaStreamInterface> mediaStream = nullptr;
169     if (mediaStreamIds.size()) {
170         // libwebrtc is only using the first one if any.
171         mediaStream = LibWebRTCProvider::factory()->CreateLocalMediaStream(mediaStreamIds[0].utf8().data());
172         mediaStreams.push_back(mediaStream.get());
173     }
174     
175     auto& source = track.source();
176     switch (source.type()) {
177     case RealtimeMediaSource::Type::Audio: {
178         auto trackSource = RealtimeOutgoingAudioSource::create(source);
179         auto audioTrack = LibWebRTCProvider::factory()->CreateAudioTrack(track.id().utf8().data(), trackSource.ptr());
180         trackSource->setTrack(rtc::scoped_refptr<webrtc::AudioTrackInterface>(audioTrack));
181         m_peerConnectionBackend.addAudioSource(WTFMove(trackSource));
182         m_backend->AddTrack(audioTrack.get(), WTFMove(mediaStreams));
183         return;
184     }
185     case RealtimeMediaSource::Type::Video: {
186         auto videoSource = RealtimeOutgoingVideoSource::create(source);
187         auto videoTrack = LibWebRTCProvider::factory()->CreateVideoTrack(track.id().utf8().data(), videoSource.ptr());
188         m_peerConnectionBackend.addVideoSource(WTFMove(videoSource));
189         m_backend->AddTrack(videoTrack.get(), WTFMove(mediaStreams));
190         return;
191     }
192     case RealtimeMediaSource::Type::None:
193         ASSERT_NOT_REACHED();
194     }
195 }
196
197 void LibWebRTCMediaEndpoint::doCreateOffer()
198 {
199     if (!LibWebRTCProvider::factory()) {
200         m_peerConnectionBackend.createOfferFailed(Exception { NOT_SUPPORTED_ERR, ASCIILiteral("libwebrtc backend is missing.") });
201         return;
202     }
203         
204     m_isInitiator = true;
205     m_backend->CreateOffer(&m_createSessionDescriptionObserver, nullptr);
206 }
207
208 void LibWebRTCMediaEndpoint::doCreateAnswer()
209 {
210     if (!LibWebRTCProvider::factory()) {
211         m_peerConnectionBackend.createAnswerFailed(Exception { NOT_SUPPORTED_ERR, ASCIILiteral("libwebrtc backend is missing.") });
212         return;
213     }
214
215     m_isInitiator = false;
216     m_backend->CreateAnswer(&m_createSessionDescriptionObserver, nullptr);
217 }
218
219 void LibWebRTCMediaEndpoint::getStats(MediaStreamTrack* track, const DeferredPromise& promise)
220 {
221     UNUSED_PARAM(track);
222     UNUSED_PARAM(promise);
223     m_backend->GetStats(StatsCollector::create(*this, promise, track).get());
224 }
225
226 LibWebRTCMediaEndpoint::StatsCollector::StatsCollector(Ref<LibWebRTCMediaEndpoint>&& endpoint, const DeferredPromise& promise, MediaStreamTrack* track)
227     : m_endpoint(WTFMove(endpoint))
228     , m_promise(promise)
229 {
230     if (track)
231         m_id = track->id();
232 }
233
234 static inline String fromStdString(const std::string& value)
235 {
236     return String(value.data(), value.length());
237 }
238
239 static inline void fillRTCStats(RTCStatsReport::Stats& stats, const webrtc::RTCStats& rtcStats)
240 {
241     stats.timestamp = rtcStats.timestamp_us();
242     stats.id = fromStdString(rtcStats.id());
243 }
244
245 static inline void fillRTCRTPStreamStats(RTCStatsReport::RTCRTPStreamStats& stats, const webrtc::RTCRTPStreamStats& rtcStats)
246 {
247     fillRTCStats(stats, rtcStats);
248     if (rtcStats.ssrc.is_defined())
249         stats.ssrc = *rtcStats.ssrc;
250     if (rtcStats.associate_stats_id.is_defined())
251         stats.associateStatsId = fromStdString(*rtcStats.associate_stats_id);
252     if (rtcStats.is_remote.is_defined())
253         stats.isRemote = *rtcStats.is_remote;
254     if (rtcStats.media_type.is_defined())
255         stats.mediaType = fromStdString(*rtcStats.media_type);
256     if (rtcStats.track_id.is_defined())
257         stats.mediaTrackId = fromStdString(*rtcStats.track_id);
258     if (rtcStats.transport_id.is_defined())
259         stats.transportId = fromStdString(*rtcStats.transport_id);
260     if (rtcStats.codec_id.is_defined())
261         stats.codecId = fromStdString(*rtcStats.codec_id);
262     if (rtcStats.fir_count.is_defined())
263         stats.firCount = *rtcStats.fir_count;
264     if (rtcStats.pli_count.is_defined())
265         stats.pliCount = *rtcStats.pli_count;
266     if (rtcStats.nack_count.is_defined())
267         stats.nackCount = *rtcStats.nack_count;
268     if (rtcStats.sli_count.is_defined())
269         stats.sliCount = *rtcStats.sli_count;
270     // FIXME: Set qpSum
271     stats.qpSum = 0;
272 }
273
274 static inline void fillInboundRTPStreamStats(RTCStatsReport::InboundRTPStreamStats& stats, const webrtc::RTCInboundRTPStreamStats& rtcStats)
275 {
276     fillRTCRTPStreamStats(stats, rtcStats);
277     if (rtcStats.packets_received.is_defined())
278         stats.packetsReceived = *rtcStats.packets_received;
279     if (rtcStats.bytes_received.is_defined())
280         stats.bytesReceived = *rtcStats.bytes_received;
281     if (rtcStats.packets_lost.is_defined())
282         stats.packetsLost = *rtcStats.packets_lost;
283     if (rtcStats.jitter.is_defined())
284         stats.jitter = *rtcStats.jitter;
285     if (rtcStats.fraction_lost.is_defined())
286         stats.fractionLost = *rtcStats.fraction_lost;
287     if (rtcStats.packets_discarded.is_defined())
288         stats.packetsDiscarded = *rtcStats.packets_discarded;
289     if (rtcStats.packets_repaired.is_defined())
290         stats.packetsRepaired = *rtcStats.packets_repaired;
291     if (rtcStats.burst_packets_lost.is_defined())
292         stats.burstPacketsLost = *rtcStats.burst_packets_lost;
293     if (rtcStats.burst_packets_discarded.is_defined())
294         stats.burstPacketsDiscarded = *rtcStats.burst_packets_discarded;
295     if (rtcStats.burst_loss_count.is_defined())
296         stats.burstLossCount = *rtcStats.burst_loss_count;
297     if (rtcStats.burst_discard_count.is_defined())
298         stats.burstDiscardCount = *rtcStats.burst_discard_count;
299     if (rtcStats.burst_loss_rate.is_defined())
300         stats.burstLossRate = *rtcStats.burst_loss_rate;
301     if (rtcStats.burst_discard_rate.is_defined())
302         stats.burstDiscardRate = *rtcStats.burst_discard_rate;
303     if (rtcStats.gap_loss_rate.is_defined())
304         stats.gapLossRate = *rtcStats.gap_loss_rate;
305     if (rtcStats.gap_discard_rate.is_defined())
306         stats.gapDiscardRate = *rtcStats.gap_discard_rate;
307     // FIXME: Set framesDecoded
308     stats.framesDecoded = 0;
309 }
310
311 static inline void fillOutboundRTPStreamStats(RTCStatsReport::OutboundRTPStreamStats& stats, const webrtc::RTCOutboundRTPStreamStats& rtcStats)
312 {
313     fillRTCRTPStreamStats(stats, rtcStats);
314
315     if (rtcStats.packets_sent.is_defined())
316         stats.packetsSent = *rtcStats.packets_sent;
317     if (rtcStats.bytes_sent.is_defined())
318         stats.bytesSent = *rtcStats.bytes_sent;
319     if (rtcStats.target_bitrate.is_defined())
320         stats.targetBitrate = *rtcStats.target_bitrate;
321     // FIXME: Set framesEncoded
322     stats.framesEncoded = 0;
323 }
324
325 void LibWebRTCMediaEndpoint::StatsCollector::OnStatsDelivered(const rtc::scoped_refptr<const webrtc::RTCStatsReport>& rtcReport)
326 {
327     callOnMainThread([protectedThis = rtc::scoped_refptr<LibWebRTCMediaEndpoint::StatsCollector>(this), rtcReport] {
328         if (protectedThis->m_endpoint->isStopped())
329             return;
330
331         auto report = RTCStatsReport::create();
332         protectedThis->m_endpoint->m_peerConnectionBackend.getStatsSucceeded(protectedThis->m_promise, report.copyRef());
333         ASSERT(report->backingMap());
334
335         for (const auto& rtcStats : *rtcReport) {
336             if (rtcStats.type() == webrtc::RTCInboundRTPStreamStats::kType) {
337                 RTCStatsReport::InboundRTPStreamStats stats;
338                 fillInboundRTPStreamStats(stats, static_cast<const webrtc::RTCInboundRTPStreamStats&>(rtcStats));
339                 report->addStats<IDLDictionary<RTCStatsReport::InboundRTPStreamStats>>(WTFMove(stats));
340                 return;
341             }
342             if (rtcStats.type() == webrtc::RTCOutboundRTPStreamStats::kType) {
343                 RTCStatsReport::OutboundRTPStreamStats stats;
344                 fillOutboundRTPStreamStats(stats, static_cast<const webrtc::RTCOutboundRTPStreamStats&>(rtcStats));
345                 report->addStats<IDLDictionary<RTCStatsReport::OutboundRTPStreamStats>>(WTFMove(stats));
346                 return;
347             }
348         }
349     });
350 }
351
352 static RTCSignalingState signalingState(webrtc::PeerConnectionInterface::SignalingState state)
353 {
354     switch (state) {
355     case webrtc::PeerConnectionInterface::kStable:
356         return RTCSignalingState::Stable;
357     case webrtc::PeerConnectionInterface::kHaveLocalOffer:
358         return RTCSignalingState::HaveLocalOffer;
359     case webrtc::PeerConnectionInterface::kHaveLocalPrAnswer:
360         return RTCSignalingState::HaveLocalPranswer;
361     case webrtc::PeerConnectionInterface::kHaveRemoteOffer:
362         return RTCSignalingState::HaveRemoteOffer;
363     case webrtc::PeerConnectionInterface::kHaveRemotePrAnswer:
364         return RTCSignalingState::HaveRemotePranswer;
365     case webrtc::PeerConnectionInterface::kClosed:
366         return RTCSignalingState::Closed;
367     }
368 }
369
370 void LibWebRTCMediaEndpoint::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState rtcState)
371 {
372     auto state = signalingState(rtcState);
373     callOnMainThread([protectedThis = makeRef(*this), state] {
374         if (protectedThis->isStopped())
375             return;
376         protectedThis->m_peerConnectionBackend.updateSignalingState(state);
377     });
378 }
379
380 static inline String trackId(webrtc::MediaStreamTrackInterface& videoTrack)
381 {
382     return String(videoTrack.id().data(), videoTrack.id().size());
383 }
384
385 static inline Ref<MediaStreamTrack> createMediaStreamTrack(ScriptExecutionContext& context, Ref<RealtimeMediaSource>&& remoteSource)
386 {
387     String trackId = remoteSource->id();
388     return MediaStreamTrack::create(context, MediaStreamTrackPrivate::create(WTFMove(remoteSource), WTFMove(trackId)));
389 }
390
391 void LibWebRTCMediaEndpoint::addStream(webrtc::MediaStreamInterface& stream)
392 {
393     MediaStreamTrackVector tracks;
394     for (auto& videoTrack : stream.GetVideoTracks()) {
395         ASSERT(videoTrack);
396         String id = trackId(*videoTrack);
397         auto remoteSource = RealtimeIncomingVideoSource::create(WTFMove(videoTrack), WTFMove(id));
398         tracks.append(createMediaStreamTrack(*m_peerConnectionBackend.connection().scriptExecutionContext(), WTFMove(remoteSource)));
399     }
400     for (auto& audioTrack : stream.GetAudioTracks()) {
401         ASSERT(audioTrack);
402         String id = trackId(*audioTrack);
403         auto remoteSource = RealtimeIncomingAudioSource::create(WTFMove(audioTrack), WTFMove(id));
404         tracks.append(createMediaStreamTrack(*m_peerConnectionBackend.connection().scriptExecutionContext(), WTFMove(remoteSource)));
405     }
406
407     auto newStream = MediaStream::create(*m_peerConnectionBackend.connection().scriptExecutionContext(), WTFMove(tracks));
408     m_peerConnectionBackend.connection().fireEvent(MediaStreamEvent::create(eventNames().addstreamEvent, false, false, newStream.copyRef()));
409
410     Vector<RefPtr<MediaStream>> streams;
411     streams.append(newStream.copyRef());
412     for (auto& track : newStream->getTracks())
413         m_peerConnectionBackend.connection().fireEvent(RTCTrackEvent::create(eventNames().trackEvent, false, false, nullptr, track.get(), Vector<RefPtr<MediaStream>>(streams), nullptr));
414 }
415
416 void LibWebRTCMediaEndpoint::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)
417 {
418     callOnMainThread([protectedThis = makeRef(*this), stream = WTFMove(stream)] {
419         if (protectedThis->isStopped())
420             return;
421         ASSERT(stream);
422         protectedThis->addStream(*stream.get());
423     });
424 }
425
426 void LibWebRTCMediaEndpoint::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface>)
427 {
428     notImplemented();
429 }
430
431 std::unique_ptr<RTCDataChannelHandler> LibWebRTCMediaEndpoint::createDataChannel(const String& label, const RTCDataChannelInit& options)
432 {
433     webrtc::DataChannelInit init;
434     init.ordered = options.ordered;
435     init.maxRetransmitTime = options.maxRetransmitTime;
436     init.maxRetransmits = options.maxRetransmits;
437     init.protocol = options.protocol.utf8().data();
438     init.negotiated = options.negotiated;
439     init.id = options.id;
440
441     return std::make_unique<LibWebRTCDataChannelHandler>(m_backend->CreateDataChannel(label.utf8().data(), &init));
442 }
443
444 void LibWebRTCMediaEndpoint::addDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface>&& dataChannel)
445 {
446     auto protocol = dataChannel->protocol();
447     auto label = dataChannel->label();
448
449     RTCDataChannelInit init;
450     init.ordered = dataChannel->ordered();
451     init.maxRetransmitTime = dataChannel->maxRetransmitTime();
452     init.maxRetransmits = dataChannel->maxRetransmits();
453     init.protocol = String(protocol.data(), protocol.size());
454     init.negotiated = dataChannel->negotiated();
455     init.id = dataChannel->id();
456
457     bool isOpened = dataChannel->state() == webrtc::DataChannelInterface::kOpen;
458
459     auto handler =  std::make_unique<LibWebRTCDataChannelHandler>(WTFMove(dataChannel));
460     ASSERT(m_peerConnectionBackend.connection().scriptExecutionContext());
461     auto channel = RTCDataChannel::create(*m_peerConnectionBackend.connection().scriptExecutionContext(), WTFMove(handler), String(label.data(), label.size()), WTFMove(init));
462
463     if (isOpened) {
464         callOnMainThread([channel = channel.copyRef()] {
465             // FIXME: We should be able to write channel->didChangeReadyState(...)
466             RTCDataChannelHandlerClient& client = channel.get();
467             client.didChangeReadyState(RTCDataChannel::ReadyStateOpen);
468         });
469     }
470
471     m_peerConnectionBackend.connection().fireEvent(RTCDataChannelEvent::create(eventNames().datachannelEvent, false, false, WTFMove(channel)));
472 }
473
474 void LibWebRTCMediaEndpoint::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel)
475 {
476     callOnMainThread([protectedThis = makeRef(*this), dataChannel = WTFMove(dataChannel)] {
477         if (protectedThis->isStopped())
478             return;
479         protectedThis->addDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface>(dataChannel));
480     });
481 }
482
483 void LibWebRTCMediaEndpoint::stop()
484 {
485     ASSERT(m_backend);
486     m_backend->Close();
487     m_backend = nullptr;
488 }
489
490 void LibWebRTCMediaEndpoint::OnRenegotiationNeeded()
491 {
492     callOnMainThread([protectedThis = makeRef(*this)] {
493         if (protectedThis->isStopped())
494             return;
495         protectedThis->m_peerConnectionBackend.markAsNeedingNegotiation();
496     });
497 }
498
499 static inline RTCIceConnectionState toRTCIceConnectionState(webrtc::PeerConnectionInterface::IceConnectionState state)
500 {
501     switch (state) {
502     case webrtc::PeerConnectionInterface::kIceConnectionNew:
503         return RTCIceConnectionState::New;
504     case webrtc::PeerConnectionInterface::kIceConnectionChecking:
505         return RTCIceConnectionState::Checking;
506     case webrtc::PeerConnectionInterface::kIceConnectionConnected:
507         return RTCIceConnectionState::Connected;
508     case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
509         return RTCIceConnectionState::Completed;
510     case webrtc::PeerConnectionInterface::kIceConnectionFailed:
511         return RTCIceConnectionState::Failed;
512     case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
513         return RTCIceConnectionState::Disconnected;
514     case webrtc::PeerConnectionInterface::kIceConnectionClosed:
515         return RTCIceConnectionState::Closed;
516     case webrtc::PeerConnectionInterface::kIceConnectionMax:
517         ASSERT_NOT_REACHED();
518         return RTCIceConnectionState::New;
519     }
520 }
521
522 void LibWebRTCMediaEndpoint::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState state)
523 {
524     auto connectionState = toRTCIceConnectionState(state);
525     callOnMainThread([protectedThis = makeRef(*this), connectionState] {
526         if (protectedThis->isStopped())
527             return;
528         if (protectedThis->m_peerConnectionBackend.connection().iceConnectionState() != connectionState)
529             protectedThis->m_peerConnectionBackend.connection().updateIceConnectionState(connectionState);
530     });
531 }
532
533 void LibWebRTCMediaEndpoint::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState state)
534 {
535     if (state == webrtc::PeerConnectionInterface::kIceGatheringComplete) {
536         callOnMainThread([protectedThis = makeRef(*this)] {
537             if (protectedThis->isStopped())
538                 return;
539             protectedThis->m_peerConnectionBackend.doneGatheringCandidates();
540         });
541     }
542 }
543
544 void LibWebRTCMediaEndpoint::OnIceCandidate(const webrtc::IceCandidateInterface *rtcCandidate)
545 {
546     ASSERT(rtcCandidate);
547
548     std::string sdp;
549     rtcCandidate->ToString(&sdp);
550     String candidateSDP(sdp.data(), sdp.size());
551
552     auto mid = rtcCandidate->sdp_mid();
553     String candidateMid(mid.data(), mid.size());
554
555     callOnMainThread([protectedThis = makeRef(*this), mid = WTFMove(candidateMid), sdp = WTFMove(candidateSDP)] {
556         if (protectedThis->isStopped())
557             return;
558         protectedThis->m_peerConnectionBackend.newICECandidate(String(sdp), String(mid));
559     });
560 }
561
562 void LibWebRTCMediaEndpoint::OnIceCandidatesRemoved(const std::vector<cricket::Candidate>&)
563 {
564     ASSERT_NOT_REACHED();
565 }
566
567 void LibWebRTCMediaEndpoint::createSessionDescriptionSucceeded(webrtc::SessionDescriptionInterface* description)
568 {
569     std::string sdp;
570     description->ToString(&sdp);
571     String sdpString(sdp.data(), sdp.size());
572
573     callOnMainThread([protectedThis = makeRef(*this), sdp = WTFMove(sdpString)] {
574         if (protectedThis->isStopped())
575             return;
576         if (protectedThis->m_isInitiator)
577             protectedThis->m_peerConnectionBackend.createOfferSucceeded(String(sdp));
578         else
579             protectedThis->m_peerConnectionBackend.createAnswerSucceeded(String(sdp));
580     });
581 }
582
583 void LibWebRTCMediaEndpoint::createSessionDescriptionFailed(const std::string& errorMessage)
584 {
585     String error(errorMessage.data(), errorMessage.size());
586     callOnMainThread([protectedThis = makeRef(*this), error = WTFMove(error)] {
587         if (protectedThis->isStopped())
588             return;
589         if (protectedThis->m_isInitiator)
590             protectedThis->m_peerConnectionBackend.createOfferFailed(Exception { OperationError, String(error) });
591         else
592             protectedThis->m_peerConnectionBackend.createAnswerFailed(Exception { OperationError, String(error) });
593     });
594 }
595
596 void LibWebRTCMediaEndpoint::setLocalSessionDescriptionSucceeded()
597 {
598     callOnMainThread([protectedThis = makeRef(*this)] {
599         if (protectedThis->isStopped())
600             return;
601         protectedThis->m_peerConnectionBackend.setLocalDescriptionSucceeded();
602     });
603 }
604
605 void LibWebRTCMediaEndpoint::setLocalSessionDescriptionFailed(const std::string& errorMessage)
606 {
607     String error(errorMessage.data(), errorMessage.size());
608     callOnMainThread([protectedThis = makeRef(*this), error = WTFMove(error)] {
609         if (protectedThis->isStopped())
610             return;
611         protectedThis->m_peerConnectionBackend.setLocalDescriptionFailed(Exception { OperationError, String(error) });
612     });
613 }
614
615 void LibWebRTCMediaEndpoint::setRemoteSessionDescriptionSucceeded()
616 {
617     callOnMainThread([protectedThis = makeRef(*this)] {
618         if (protectedThis->isStopped())
619             return;
620         protectedThis->m_peerConnectionBackend.setRemoteDescriptionSucceeded();
621     });
622 }
623
624 void LibWebRTCMediaEndpoint::setRemoteSessionDescriptionFailed(const std::string& errorMessage)
625 {
626     String error(errorMessage.data(), errorMessage.size());
627     callOnMainThread([protectedThis = makeRef(*this), error = WTFMove(error)] {
628         if (protectedThis->isStopped())
629             return;
630         protectedThis->m_peerConnectionBackend.setRemoteDescriptionFailed(Exception { OperationError, String(error) });
631     });
632 }
633
634 } // namespace WebCore
635
636 #endif // USE(LIBWEBRTC)