2 * Copyright (C) 2015 Ericsson AB. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * 3. Neither the name of Ericsson nor the names of its contributors
15 * may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "MediaEndpointPeerConnection.h"
36 #include "EventNames.h"
37 #include "JSRTCSessionDescription.h"
38 #include "MediaEndpointSessionConfiguration.h"
39 #include "MediaStream.h"
40 #include "MediaStreamEvent.h"
41 #include "MediaStreamTrack.h"
42 #include "NotImplemented.h"
43 #include "PeerMediaDescription.h"
44 #include "RTCConfiguration.h"
45 #include "RTCIceCandidate.h"
46 #include "RTCIceCandidateEvent.h"
47 #include "RTCOfferAnswerOptions.h"
48 #include "RTCRtpTransceiver.h"
49 #include "RTCTrackEvent.h"
50 #include "SDPProcessor.h"
51 #include <wtf/MainThread.h>
52 #include <wtf/text/Base64.h>
56 using namespace PeerConnection;
57 using namespace PeerConnectionStates;
59 // We use base64 to generate the random strings so we need a size that avoids padding to get ice-chars.
60 static const size_t cnameSize = 18;
61 // Size range from 4 to 256 ice-chars defined in RFC 5245.
62 static const size_t iceUfragSize = 6;
63 // Size range from 22 to 256 ice-chars defined in RFC 5245.
64 static const size_t icePasswordSize = 24;
66 static std::unique_ptr<PeerConnectionBackend> createMediaEndpointPeerConnection(PeerConnectionBackendClient* client)
68 return std::unique_ptr<PeerConnectionBackend>(new MediaEndpointPeerConnection(client));
71 CreatePeerConnectionBackend PeerConnectionBackend::create = createMediaEndpointPeerConnection;
73 static String randomString(size_t size)
75 unsigned char randomValues[size];
76 cryptographicallyRandomValues(randomValues, size);
77 return base64Encode(randomValues, size);
80 MediaEndpointPeerConnection::MediaEndpointPeerConnection(PeerConnectionBackendClient* client)
82 , m_mediaEndpoint(MediaEndpoint::create(*this))
83 , m_sdpProcessor(std::unique_ptr<SDPProcessor>(new SDPProcessor(m_client->scriptExecutionContext())))
84 , m_cname(randomString(cnameSize))
85 , m_iceUfrag(randomString(iceUfragSize))
86 , m_icePassword(randomString(icePasswordSize))
88 ASSERT(m_mediaEndpoint);
90 m_defaultAudioPayloads = m_mediaEndpoint->getDefaultAudioPayloads();
91 m_defaultVideoPayloads = m_mediaEndpoint->getDefaultVideoPayloads();
93 // Tasks (see runTask()) will be deferred until we get the DTLS fingerprint.
94 m_mediaEndpoint->generateDtlsInfo();
97 static RTCRtpTransceiver* matchTransceiver(const RtpTransceiverVector& transceivers, const std::function<bool(RTCRtpTransceiver&)>& matchFunction)
99 for (auto& transceiver : transceivers) {
100 if (matchFunction(*transceiver))
101 return transceiver.get();
106 static RTCRtpTransceiver* matchTransceiverByMid(const RtpTransceiverVector& transceivers, const String& mid)
108 return matchTransceiver(transceivers, [&mid] (RTCRtpTransceiver& current) {
109 return current.mid() == mid;
113 static bool hasUnassociatedTransceivers(const RtpTransceiverVector& transceivers)
115 return matchTransceiver(transceivers, [] (RTCRtpTransceiver& current) {
116 return current.mid().isNull() && !current.stopped();
120 void MediaEndpointPeerConnection::runTask(Function<void ()>&& task)
122 if (m_dtlsFingerprint.isNull()) {
123 // Only one task needs to be deferred since it will hold off any others until completed.
124 ASSERT(!m_initialDeferredTask);
125 m_initialDeferredTask = WTFMove(task);
127 callOnMainThread(WTFMove(task));
130 void MediaEndpointPeerConnection::startRunningTasks()
132 if (!m_initialDeferredTask)
135 m_initialDeferredTask();
136 m_initialDeferredTask = nullptr;
139 void MediaEndpointPeerConnection::createOffer(RTCOfferOptions& options, SessionDescriptionPromise&& promise)
141 runTask([this, protectedOptions = RefPtr<RTCOfferOptions>(&options), protectedPromise = WTFMove(promise)]() mutable {
142 createOfferTask(*protectedOptions, protectedPromise);
146 void MediaEndpointPeerConnection::createOfferTask(RTCOfferOptions&, SessionDescriptionPromise& promise)
148 ASSERT(!m_dtlsFingerprint.isEmpty());
150 if (m_client->internalSignalingState() == SignalingState::Closed)
153 MediaEndpointSessionDescription* localDescription = internalLocalDescription();
154 RefPtr<MediaEndpointSessionConfiguration> configurationSnapshot = localDescription ?
155 localDescription->configuration()->clone() : MediaEndpointSessionConfiguration::create();
157 configurationSnapshot->setSessionVersion(m_sdpOfferSessionVersion++);
159 auto transceivers = RtpTransceiverVector(m_client->getTransceivers());
161 // Remove any transceiver objects from transceivers that can be matched to an existing media description.
162 for (auto& mediaDescription : configurationSnapshot->mediaDescriptions()) {
163 if (!mediaDescription->port()) {
164 // This media description should be recycled.
168 RTCRtpTransceiver* transceiver = matchTransceiverByMid(transceivers, mediaDescription->mid());
172 mediaDescription->setMode(transceiver->directionString());
173 if (transceiver->hasSendingDirection()) {
174 RTCRtpSender& sender = *transceiver->sender();
176 mediaDescription->setMediaStreamId(sender.mediaStreamIds()[0]);
177 mediaDescription->setMediaStreamTrackId(sender.trackId());
180 transceivers.removeFirst(transceiver);
183 // Add media descriptions for remaining transceivers.
184 for (auto& transceiver : transceivers) {
185 RefPtr<PeerMediaDescription> mediaDescription = PeerMediaDescription::create();
186 RTCRtpSender& sender = *transceiver->sender();
188 mediaDescription->setMode(transceiver->directionString());
189 mediaDescription->setMid(transceiver->provisionalMid());
190 mediaDescription->setMediaStreamId(sender.mediaStreamIds()[0]);
191 mediaDescription->setType(sender.trackKind());
192 mediaDescription->setPayloads(sender.trackKind() == "audio" ? m_defaultAudioPayloads : m_defaultVideoPayloads);
193 mediaDescription->setDtlsFingerprintHashFunction(m_dtlsFingerprintFunction);
194 mediaDescription->setDtlsFingerprint(m_dtlsFingerprint);
195 mediaDescription->setCname(m_cname);
196 mediaDescription->addSsrc(cryptographicallyRandomNumber());
197 mediaDescription->setIceUfrag(m_iceUfrag);
198 mediaDescription->setIcePassword(m_icePassword);
201 mediaDescription->setMediaStreamTrackId(sender.trackId());
203 configurationSnapshot->addMediaDescription(WTFMove(mediaDescription));
206 auto description = MediaEndpointSessionDescription::create(RTCSessionDescription::SdpType::Offer, WTFMove(configurationSnapshot));
207 promise.resolve(*description->toRTCSessionDescription(*m_sdpProcessor));
210 void MediaEndpointPeerConnection::createAnswer(RTCAnswerOptions& options, SessionDescriptionPromise&& promise)
212 runTask([this, protectedOptions = RefPtr<RTCAnswerOptions>(&options), protectedPromise = WTFMove(promise)]() mutable {
213 createAnswerTask(*protectedOptions, protectedPromise);
217 void MediaEndpointPeerConnection::createAnswerTask(RTCAnswerOptions&, SessionDescriptionPromise& promise)
219 ASSERT(!m_dtlsFingerprint.isEmpty());
221 if (m_client->internalSignalingState() == SignalingState::Closed)
224 if (!internalRemoteDescription()) {
225 promise.reject(INVALID_STATE_ERR, "No remote description set");
229 MediaEndpointSessionDescription* localDescription = internalLocalDescription();
230 RefPtr<MediaEndpointSessionConfiguration> configurationSnapshot = localDescription ?
231 localDescription->configuration()->clone() : MediaEndpointSessionConfiguration::create();
233 configurationSnapshot->setSessionVersion(m_sdpAnswerSessionVersion++);
235 auto transceivers = RtpTransceiverVector(m_client->getTransceivers());
236 const MediaDescriptionVector& remoteMediaDescriptions = internalRemoteDescription()->configuration()->mediaDescriptions();
238 for (unsigned i = 0; i < remoteMediaDescriptions.size(); ++i) {
239 PeerMediaDescription& remoteMediaDescription = *remoteMediaDescriptions[i];
241 RTCRtpTransceiver* transceiver = matchTransceiverByMid(transceivers, remoteMediaDescription.mid());
243 LOG_ERROR("Could not find a matching transceiver for remote description while creating answer");
247 if (i >= configurationSnapshot->mediaDescriptions().size()) {
248 auto newMediaDescription = PeerMediaDescription::create();
250 RTCRtpSender& sender = *transceiver->sender();
251 if (sender.track()) {
252 if (sender.mediaStreamIds().size())
253 newMediaDescription->setMediaStreamId(sender.mediaStreamIds()[0]);
254 newMediaDescription->setMediaStreamTrackId(sender.trackId());
255 newMediaDescription->addSsrc(cryptographicallyRandomNumber());
258 newMediaDescription->setMode(transceiver->directionString());
259 newMediaDescription->setType(remoteMediaDescription.type());
260 newMediaDescription->setMid(remoteMediaDescription.mid());
261 newMediaDescription->setDtlsSetup(remoteMediaDescription.dtlsSetup() == "active" ? "passive" : "active");
262 newMediaDescription->setDtlsFingerprintHashFunction(m_dtlsFingerprintFunction);
263 newMediaDescription->setDtlsFingerprint(m_dtlsFingerprint);
264 newMediaDescription->setCname(m_cname);
265 newMediaDescription->setIceUfrag(m_iceUfrag);
266 newMediaDescription->setIcePassword(m_icePassword);
268 configurationSnapshot->addMediaDescription(WTFMove(newMediaDescription));
271 PeerMediaDescription& localMediaDescription = *configurationSnapshot->mediaDescriptions()[i];
273 localMediaDescription.setPayloads(remoteMediaDescription.payloads());
274 localMediaDescription.setRtcpMux(remoteMediaDescription.rtcpMux());
276 if (!localMediaDescription.ssrcs().size())
277 localMediaDescription.addSsrc(cryptographicallyRandomNumber());
279 if (localMediaDescription.dtlsSetup() == "actpass")
280 localMediaDescription.setDtlsSetup("passive");
282 transceivers.removeFirst(transceiver);
285 // Unassociated (non-stopped) transceivers need to be negotiated in a follow-up offer.
286 if (hasUnassociatedTransceivers(transceivers))
287 markAsNeedingNegotiation();
289 auto description = MediaEndpointSessionDescription::create(RTCSessionDescription::SdpType::Answer, WTFMove(configurationSnapshot));
290 promise.resolve(*description->toRTCSessionDescription(*m_sdpProcessor));
293 static RealtimeMediaSourceMap createSourceMap(const MediaDescriptionVector& remoteMediaDescriptions, unsigned localMediaDescriptionCount, const RtpTransceiverVector& transceivers)
295 RealtimeMediaSourceMap sourceMap;
297 for (unsigned i = 0; i < remoteMediaDescriptions.size() && i < localMediaDescriptionCount; ++i) {
298 PeerMediaDescription& remoteMediaDescription = *remoteMediaDescriptions[i];
299 if (remoteMediaDescription.type() != "audio" && remoteMediaDescription.type() != "video")
302 RTCRtpTransceiver* transceiver = matchTransceiverByMid(transceivers, remoteMediaDescription.mid());
304 if (transceiver->hasSendingDirection() && transceiver->sender()->track())
305 sourceMap.set(transceiver->mid(), &transceiver->sender()->track()->source());
312 void MediaEndpointPeerConnection::setLocalDescription(RTCSessionDescription& description, VoidPromise&& promise)
314 runTask([this, protectedDescription = RefPtr<RTCSessionDescription>(&description), protectedPromise = WTFMove(promise)]() mutable {
315 setLocalDescriptionTask(WTFMove(protectedDescription), protectedPromise);
319 void MediaEndpointPeerConnection::setLocalDescriptionTask(RefPtr<RTCSessionDescription>&& description, VoidPromise& promise)
321 if (m_client->internalSignalingState() == SignalingState::Closed)
324 auto result = MediaEndpointSessionDescription::create(WTFMove(description), *m_sdpProcessor);
325 if (result.hasException()) {
326 promise.reject(result.releaseException());
329 auto newDescription = result.releaseReturnValue();
331 if (!localDescriptionTypeValidForState(newDescription->type())) {
332 promise.reject(INVALID_STATE_ERR, "Description type incompatible with current signaling state");
336 const RtpTransceiverVector& transceivers = m_client->getTransceivers();
337 const MediaDescriptionVector& mediaDescriptions = newDescription->configuration()->mediaDescriptions();
338 MediaEndpointSessionDescription* localDescription = internalLocalDescription();
339 unsigned previousNumberOfMediaDescriptions = localDescription ? localDescription->configuration()->mediaDescriptions().size() : 0;
340 bool hasNewMediaDescriptions = mediaDescriptions.size() > previousNumberOfMediaDescriptions;
341 bool isInitiator = newDescription->type() == RTCSessionDescription::SdpType::Offer;
343 if (hasNewMediaDescriptions) {
344 MediaEndpoint::UpdateResult result = m_mediaEndpoint->updateReceiveConfiguration(newDescription->configuration(), isInitiator);
346 if (result == MediaEndpoint::UpdateResult::SuccessWithIceRestart) {
347 if (m_client->internalIceGatheringState() != IceGatheringState::Gathering)
348 m_client->updateIceGatheringState(IceGatheringState::Gathering);
350 if (m_client->internalIceConnectionState() != IceConnectionState::Completed)
351 m_client->updateIceConnectionState(IceConnectionState::Connected);
353 LOG_ERROR("ICE restart is not implemented");
356 } else if (result == MediaEndpoint::UpdateResult::Failed) {
357 promise.reject(OperationError, "Unable to apply session description");
361 // Associate media descriptions with transceivers (set provisional mid to 'final' mid).
362 for (unsigned i = previousNumberOfMediaDescriptions; i < mediaDescriptions.size(); ++i) {
363 PeerMediaDescription& mediaDescription = *mediaDescriptions[i];
365 RTCRtpTransceiver* transceiver = matchTransceiver(transceivers, [&mediaDescription] (RTCRtpTransceiver& current) {
366 return current.provisionalMid() == mediaDescription.mid();
369 transceiver->setMid(transceiver->provisionalMid());
373 if (internalRemoteDescription()) {
374 MediaEndpointSessionConfiguration* remoteConfiguration = internalRemoteDescription()->configuration();
375 RealtimeMediaSourceMap sendSourceMap = createSourceMap(remoteConfiguration->mediaDescriptions(), mediaDescriptions.size(), transceivers);
377 if (m_mediaEndpoint->updateSendConfiguration(remoteConfiguration, sendSourceMap, isInitiator) == MediaEndpoint::UpdateResult::Failed) {
378 promise.reject(OperationError, "Unable to apply session description");
383 if (!hasUnassociatedTransceivers(transceivers))
384 clearNegotiationNeededState();
386 SignalingState newSignalingState;
388 // Update state and local descriptions according to setLocal/RemoteDescription processing model
389 switch (newDescription->type()) {
390 case RTCSessionDescription::SdpType::Offer:
391 m_pendingLocalDescription = WTFMove(newDescription);
392 newSignalingState = SignalingState::HaveLocalOffer;
395 case RTCSessionDescription::SdpType::Answer:
396 m_currentLocalDescription = WTFMove(newDescription);
397 m_currentRemoteDescription = m_pendingRemoteDescription;
398 m_pendingLocalDescription = nullptr;
399 m_pendingRemoteDescription = nullptr;
400 newSignalingState = SignalingState::Stable;
403 case RTCSessionDescription::SdpType::Rollback:
404 m_pendingLocalDescription = nullptr;
405 newSignalingState = SignalingState::Stable;
408 case RTCSessionDescription::SdpType::Pranswer:
409 m_pendingLocalDescription = WTFMove(newDescription);
410 newSignalingState = SignalingState::HaveLocalPrAnswer;
414 if (newSignalingState != m_client->internalSignalingState()) {
415 m_client->setSignalingState(newSignalingState);
416 m_client->fireEvent(Event::create(eventNames().signalingstatechangeEvent, false, false));
419 if (m_client->internalIceGatheringState() == IceGatheringState::New && mediaDescriptions.size())
420 m_client->updateIceGatheringState(IceGatheringState::Gathering);
422 if (m_client->internalSignalingState() == SignalingState::Stable && m_negotiationNeeded)
423 m_client->scheduleNegotiationNeededEvent();
425 promise.resolve(nullptr);
428 RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::localDescription() const
430 return createRTCSessionDescription(internalLocalDescription());
433 RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::currentLocalDescription() const
435 return createRTCSessionDescription(m_currentLocalDescription.get());
438 RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::pendingLocalDescription() const
440 return createRTCSessionDescription(m_pendingLocalDescription.get());
443 void MediaEndpointPeerConnection::setRemoteDescription(RTCSessionDescription& description, VoidPromise&& promise)
445 runTask([this, protectedDescription = RefPtr<RTCSessionDescription>(&description), protectedPromise = WTFMove(promise)]() mutable {
446 setRemoteDescriptionTask(WTFMove(protectedDescription), protectedPromise);
450 void MediaEndpointPeerConnection::setRemoteDescriptionTask(RefPtr<RTCSessionDescription>&& description, VoidPromise& promise)
452 if (m_client->internalSignalingState() == SignalingState::Closed)
455 auto result = MediaEndpointSessionDescription::create(WTFMove(description), *m_sdpProcessor);
456 if (result.hasException()) {
457 promise.reject(result.releaseException());
460 auto newDescription = result.releaseReturnValue();
462 if (!remoteDescriptionTypeValidForState(newDescription->type())) {
463 promise.reject(INVALID_STATE_ERR, "Description type incompatible with current signaling state");
467 const MediaDescriptionVector& mediaDescriptions = newDescription->configuration()->mediaDescriptions();
468 for (auto& mediaDescription : mediaDescriptions) {
469 if (mediaDescription->type() != "audio" && mediaDescription->type() != "video")
472 mediaDescription->setPayloads(m_mediaEndpoint->filterPayloads(mediaDescription->payloads(),
473 mediaDescription->type() == "audio" ? m_defaultAudioPayloads : m_defaultVideoPayloads));
476 bool isInitiator = newDescription->type() == RTCSessionDescription::SdpType::Answer;
477 const RtpTransceiverVector& transceivers = m_client->getTransceivers();
479 RealtimeMediaSourceMap sendSourceMap;
480 if (internalLocalDescription())
481 sendSourceMap = createSourceMap(mediaDescriptions, internalLocalDescription()->configuration()->mediaDescriptions().size(), transceivers);
483 if (m_mediaEndpoint->updateSendConfiguration(newDescription->configuration(), sendSourceMap, isInitiator) == MediaEndpoint::UpdateResult::Failed) {
484 promise.reject(OperationError, "Unable to apply session description");
488 // One legacy MediaStreamEvent will be fired for every new MediaStream created as this remote description is set.
489 Vector<RefPtr<MediaStreamEvent>> legacyMediaStreamEvents;
491 for (auto mediaDescription : mediaDescriptions) {
492 RTCRtpTransceiver* transceiver = matchTransceiverByMid(transceivers, mediaDescription->mid());
494 bool receiveOnlyFlag = false;
496 if (mediaDescription->mode() == "sendrecv" || mediaDescription->mode() == "recvonly") {
497 // Try to match an existing transceiver.
498 transceiver = matchTransceiver(transceivers, [&mediaDescription] (RTCRtpTransceiver& current) {
499 return !current.stopped() && current.mid().isNull() && current.sender()->trackKind() == mediaDescription->type();
503 // This transceiver was created locally with a provisional mid. Its real mid will now be set by the remote
504 // description so we need to update the mid of the transceiver's muted source to preserve the association.
505 transceiver->setMid(mediaDescription->mid());
506 m_mediaEndpoint->replaceMutedRemoteSourceMid(transceiver->provisionalMid(), mediaDescription->mid());
508 receiveOnlyFlag = true;
512 auto sender = RTCRtpSender::create(mediaDescription->type(), Vector<String>(), m_client->senderClient());
513 auto receiver = createReceiver(mediaDescription->mid(), mediaDescription->type(), mediaDescription->mediaStreamTrackId());
515 auto newTransceiver = RTCRtpTransceiver::create(WTFMove(sender), WTFMove(receiver));
516 newTransceiver->setMid(mediaDescription->mid());
518 newTransceiver->disableSendingDirection();
520 transceiver = newTransceiver.ptr();
521 m_client->addTransceiver(WTFMove(newTransceiver));
525 if (mediaDescription->mode() == "sendrecv" || mediaDescription->mode() == "sendonly") {
526 RTCRtpReceiver& receiver = *transceiver->receiver();
527 if (receiver.isDispatched())
529 receiver.setDispatched(true);
531 Vector<String> mediaStreamIds;
532 if (!mediaDescription->mediaStreamId().isEmpty())
533 mediaStreamIds.append(mediaDescription->mediaStreamId());
535 // A remote track can be associated with 0..* MediaStreams. We create a new stream for
536 // a track in case of an unrecognized stream id, or just add the track if the stream
538 HashMap<String, RefPtr<MediaStream>> trackEventMediaStreams;
539 for (auto& id : mediaStreamIds) {
540 if (m_remoteStreamMap.contains(id)) {
541 RefPtr<MediaStream> stream = m_remoteStreamMap.get(id);
542 stream->addTrack(*receiver.track());
543 trackEventMediaStreams.add(id, WTFMove(stream));
545 auto newStream = MediaStream::create(*m_client->scriptExecutionContext(), MediaStreamTrackVector({ receiver.track() }));
546 m_remoteStreamMap.add(id, newStream.copyRef());
547 legacyMediaStreamEvents.append(MediaStreamEvent::create(eventNames().addstreamEvent, false, false, newStream.copyRef()));
548 trackEventMediaStreams.add(id, WTFMove(newStream));
552 Vector<RefPtr<MediaStream>> streams;
553 copyValuesToVector(trackEventMediaStreams, streams);
555 m_client->fireEvent(RTCTrackEvent::create(eventNames().trackEvent, false, false,
556 &receiver, receiver.track(), WTFMove(streams), transceiver));
560 // Fire legacy addstream events.
561 for (auto& event : legacyMediaStreamEvents)
562 m_client->fireEvent(*event);
564 SignalingState newSignalingState;
566 // Update state and local descriptions according to setLocal/RemoteDescription processing model
567 switch (newDescription->type()) {
568 case RTCSessionDescription::SdpType::Offer:
569 m_pendingRemoteDescription = WTFMove(newDescription);
570 newSignalingState = SignalingState::HaveRemoteOffer;
573 case RTCSessionDescription::SdpType::Answer:
574 m_currentRemoteDescription = WTFMove(newDescription);
575 m_currentLocalDescription = m_pendingLocalDescription;
576 m_pendingRemoteDescription = nullptr;
577 m_pendingLocalDescription = nullptr;
578 newSignalingState = SignalingState::Stable;
581 case RTCSessionDescription::SdpType::Rollback:
582 m_pendingRemoteDescription = nullptr;
583 newSignalingState = SignalingState::Stable;
586 case RTCSessionDescription::SdpType::Pranswer:
587 m_pendingRemoteDescription = WTFMove(newDescription);
588 newSignalingState = SignalingState::HaveRemotePrAnswer;
592 if (newSignalingState != m_client->internalSignalingState()) {
593 m_client->setSignalingState(newSignalingState);
594 m_client->fireEvent(Event::create(eventNames().signalingstatechangeEvent, false, false));
597 promise.resolve(nullptr);
600 RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::remoteDescription() const
602 return createRTCSessionDescription(internalRemoteDescription());
605 RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::currentRemoteDescription() const
607 return createRTCSessionDescription(m_currentRemoteDescription.get());
610 RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::pendingRemoteDescription() const
612 return createRTCSessionDescription(m_pendingRemoteDescription.get());
615 void MediaEndpointPeerConnection::setConfiguration(RTCConfiguration& configuration)
617 Vector<RefPtr<IceServerInfo>> iceServers;
618 for (auto& server : configuration.iceServers())
619 iceServers.append(IceServerInfo::create(server->urls(), server->credential(), server->username()));
621 m_mediaEndpoint->setConfiguration(MediaEndpointConfiguration::create(iceServers, configuration.iceTransportPolicy(), configuration.bundlePolicy()));
624 void MediaEndpointPeerConnection::addIceCandidate(RTCIceCandidate& rtcCandidate, PeerConnection::VoidPromise&& promise)
626 runTask([this, protectedCandidate = RefPtr<RTCIceCandidate>(&rtcCandidate), protectedPromise = WTFMove(promise)]() mutable {
627 addIceCandidateTask(*protectedCandidate, protectedPromise);
631 void MediaEndpointPeerConnection::addIceCandidateTask(RTCIceCandidate& rtcCandidate, PeerConnection::VoidPromise& promise)
633 if (m_client->internalSignalingState() == SignalingState::Closed)
636 if (!internalRemoteDescription()) {
637 promise.reject(INVALID_STATE_ERR, "No remote description set");
641 const MediaDescriptionVector& remoteMediaDescriptions = internalRemoteDescription()->configuration()->mediaDescriptions();
642 PeerMediaDescription* targetMediaDescription = nullptr;
644 // When identifying the target media description, sdpMid takes precedence over sdpMLineIndex
645 // if both are present.
646 if (!rtcCandidate.sdpMid().isNull()) {
647 const String& mid = rtcCandidate.sdpMid();
648 for (auto& description : remoteMediaDescriptions) {
649 if (description->mid() == mid) {
650 targetMediaDescription = description.get();
655 if (!targetMediaDescription) {
656 promise.reject(OperationError, "sdpMid did not match any media description");
659 } else if (rtcCandidate.sdpMLineIndex()) {
660 unsigned short sdpMLineIndex = rtcCandidate.sdpMLineIndex().value();
661 if (sdpMLineIndex >= remoteMediaDescriptions.size()) {
662 promise.reject(OperationError, "sdpMLineIndex is out of range");
665 targetMediaDescription = remoteMediaDescriptions[sdpMLineIndex].get();
667 ASSERT_NOT_REACHED();
671 RefPtr<IceCandidate> candidate;
672 SDPProcessor::Result result = m_sdpProcessor->parseCandidateLine(rtcCandidate.candidate(), candidate);
673 if (result != SDPProcessor::Result::Success) {
674 if (result == SDPProcessor::Result::ParseError)
675 promise.reject(OperationError, "Invalid candidate content");
677 LOG_ERROR("SDPProcessor internal error");
681 targetMediaDescription->addIceCandidate(candidate.copyRef());
683 m_mediaEndpoint->addRemoteCandidate(*candidate, targetMediaDescription->mid(), targetMediaDescription->iceUfrag(),
684 targetMediaDescription->icePassword());
686 promise.resolve(nullptr);
689 void MediaEndpointPeerConnection::getStats(MediaStreamTrack*, PeerConnection::StatsPromise&& promise)
693 promise.reject(NOT_SUPPORTED_ERR);
696 Vector<RefPtr<MediaStream>> MediaEndpointPeerConnection::getRemoteStreams() const
698 Vector<RefPtr<MediaStream>> remoteStreams;
699 copyValuesToVector(m_remoteStreamMap, remoteStreams);
700 return remoteStreams;
703 RefPtr<RTCRtpReceiver> MediaEndpointPeerConnection::createReceiver(const String& transceiverMid, const String& trackKind, const String& trackId)
705 RealtimeMediaSource::Type sourceType = trackKind == "audio" ? RealtimeMediaSource::Type::Audio : RealtimeMediaSource::Type::Video;
707 // Create a muted remote source that will be unmuted once media starts arriving.
708 auto remoteSource = m_mediaEndpoint->createMutedRemoteSource(transceiverMid, sourceType);
709 auto remoteTrackPrivate = MediaStreamTrackPrivate::create(WTFMove(remoteSource), trackId);
710 auto remoteTrack = MediaStreamTrack::create(*m_client->scriptExecutionContext(), *remoteTrackPrivate);
712 return RTCRtpReceiver::create(WTFMove(remoteTrack));
715 void MediaEndpointPeerConnection::replaceTrack(RTCRtpSender& sender, RefPtr<MediaStreamTrack>&& withTrack, PeerConnection::VoidPromise&& promise)
717 RTCRtpTransceiver* transceiver = matchTransceiver(m_client->getTransceivers(), [&sender] (RTCRtpTransceiver& current) {
718 return current.sender() == &sender;
722 const String& mid = transceiver->mid();
724 // Transceiver is not associated with a media description yet.
725 sender.setTrack(WTFMove(withTrack));
726 promise.resolve(nullptr);
730 runTask([this, protectedSender = RefPtr<RTCRtpSender>(&sender), mid, protectedTrack = WTFMove(withTrack), protectedPromise = WTFMove(promise)]() mutable {
731 replaceTrackTask(*protectedSender, mid, WTFMove(protectedTrack), protectedPromise);
735 void MediaEndpointPeerConnection::replaceTrackTask(RTCRtpSender& sender, const String& mid, RefPtr<MediaStreamTrack>&& withTrack, PeerConnection::VoidPromise& promise)
737 if (m_client->internalSignalingState() == SignalingState::Closed)
740 m_mediaEndpoint->replaceSendSource(withTrack->source(), mid);
742 sender.setTrack(WTFMove(withTrack));
743 promise.resolve(nullptr);
746 void MediaEndpointPeerConnection::stop()
751 void MediaEndpointPeerConnection::markAsNeedingNegotiation()
753 if (m_negotiationNeeded)
756 m_negotiationNeeded = true;
758 if (m_client->internalSignalingState() == SignalingState::Stable)
759 m_client->scheduleNegotiationNeededEvent();
762 void MediaEndpointPeerConnection::emulatePlatformEvent(const String& action)
764 m_mediaEndpoint->emulatePlatformEvent(action);
767 bool MediaEndpointPeerConnection::localDescriptionTypeValidForState(RTCSessionDescription::SdpType type) const
769 switch (m_client->internalSignalingState()) {
770 case SignalingState::Stable:
771 return type == RTCSessionDescription::SdpType::Offer;
772 case SignalingState::HaveLocalOffer:
773 return type == RTCSessionDescription::SdpType::Offer;
774 case SignalingState::HaveRemoteOffer:
775 return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer;
776 case SignalingState::HaveLocalPrAnswer:
777 return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer;
782 ASSERT_NOT_REACHED();
786 bool MediaEndpointPeerConnection::remoteDescriptionTypeValidForState(RTCSessionDescription::SdpType type) const
788 switch (m_client->internalSignalingState()) {
789 case SignalingState::Stable:
790 return type == RTCSessionDescription::SdpType::Offer;
791 case SignalingState::HaveLocalOffer:
792 return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer;
793 case SignalingState::HaveRemoteOffer:
794 return type == RTCSessionDescription::SdpType::Offer;
795 case SignalingState::HaveRemotePrAnswer:
796 return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer;
801 ASSERT_NOT_REACHED();
805 MediaEndpointSessionDescription* MediaEndpointPeerConnection::internalLocalDescription() const
807 return m_pendingLocalDescription ? m_pendingLocalDescription.get() : m_currentLocalDescription.get();
810 MediaEndpointSessionDescription* MediaEndpointPeerConnection::internalRemoteDescription() const
812 return m_pendingRemoteDescription ? m_pendingRemoteDescription.get() : m_currentRemoteDescription.get();
815 RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::createRTCSessionDescription(MediaEndpointSessionDescription* description) const
817 return description ? description->toRTCSessionDescription(*m_sdpProcessor) : nullptr;
820 void MediaEndpointPeerConnection::gotDtlsFingerprint(const String& fingerprint, const String& fingerprintFunction)
822 ASSERT(isMainThread());
824 m_dtlsFingerprint = fingerprint;
825 m_dtlsFingerprintFunction = fingerprintFunction;
830 void MediaEndpointPeerConnection::gotIceCandidate(const String& mid, RefPtr<IceCandidate>&& candidate)
832 ASSERT(isMainThread());
834 const MediaDescriptionVector& mediaDescriptions = internalLocalDescription()->configuration()->mediaDescriptions();
835 size_t mediaDescriptionIndex = notFound;
837 for (size_t i = 0; i < mediaDescriptions.size(); ++i) {
838 if (mediaDescriptions[i]->mid() == mid) {
839 mediaDescriptionIndex = i;
843 ASSERT(mediaDescriptionIndex != notFound);
845 PeerMediaDescription& mediaDescription = *mediaDescriptions[mediaDescriptionIndex];
846 mediaDescription.addIceCandidate(candidate.copyRef());
848 String candidateLine;
849 SDPProcessor::Result result = m_sdpProcessor->generateCandidateLine(*candidate, candidateLine);
850 if (result != SDPProcessor::Result::Success) {
851 LOG_ERROR("SDPProcessor internal error");
855 RefPtr<RTCIceCandidate> iceCandidate = RTCIceCandidate::create(candidateLine, mid, mediaDescriptionIndex);
857 m_client->fireEvent(RTCIceCandidateEvent::create(false, false, WTFMove(iceCandidate)));
860 void MediaEndpointPeerConnection::doneGatheringCandidates(const String& mid)
862 ASSERT(isMainThread());
864 RtpTransceiverVector transceivers = RtpTransceiverVector(m_client->getTransceivers());
865 RTCRtpTransceiver* notifyingTransceiver = matchTransceiverByMid(transceivers, mid);
866 ASSERT(notifyingTransceiver);
868 notifyingTransceiver->iceTransport().setGatheringState(RTCIceTransport::GatheringState::Complete);
870 // Don't notify the script if there are transceivers still gathering.
871 RTCRtpTransceiver* stillGatheringTransceiver = matchTransceiver(transceivers, [] (RTCRtpTransceiver& current) {
872 return !current.stopped() && !current.mid().isNull()
873 && current.iceTransport().gatheringState() != RTCIceTransport::GatheringState::Complete;
875 if (!stillGatheringTransceiver) {
876 m_client->fireEvent(RTCIceCandidateEvent::create(false, false, nullptr));
877 m_client->updateIceGatheringState(IceGatheringState::Complete);
881 static RTCIceTransport::TransportState deriveAggregatedIceConnectionState(const Vector<RTCIceTransport::TransportState>& states)
883 unsigned newCount = 0;
884 unsigned checkingCount = 0;
885 unsigned connectedCount = 0;
886 unsigned completedCount = 0;
887 unsigned failedCount = 0;
888 unsigned disconnectedCount = 0;
889 unsigned closedCount = 0;
891 for (auto& state : states) {
893 case RTCIceTransport::TransportState::New: ++newCount; break;
894 case RTCIceTransport::TransportState::Checking: ++checkingCount; break;
895 case RTCIceTransport::TransportState::Connected: ++connectedCount; break;
896 case RTCIceTransport::TransportState::Completed: ++completedCount; break;
897 case RTCIceTransport::TransportState::Failed: ++failedCount; break;
898 case RTCIceTransport::TransportState::Disconnected: ++disconnectedCount; break;
899 case RTCIceTransport::TransportState::Closed: ++closedCount; break;
903 // The aggregated RTCIceConnectionState is derived from the RTCIceTransportState of all RTCIceTransports.
904 if ((newCount > 0 && !checkingCount && !failedCount && !disconnectedCount) || (closedCount == states.size()))
905 return RTCIceTransport::TransportState::New;
907 if (checkingCount > 0 && !failedCount && !disconnectedCount)
908 return RTCIceTransport::TransportState::Checking;
910 if ((connectedCount + completedCount + closedCount) == states.size() && connectedCount > 0)
911 return RTCIceTransport::TransportState::Connected;
913 if ((completedCount + closedCount) == states.size() && completedCount > 0)
914 return RTCIceTransport::TransportState::Completed;
917 return RTCIceTransport::TransportState::Failed;
919 if (disconnectedCount > 0) // Any failed caught above.
920 return RTCIceTransport::TransportState::Disconnected;
922 ASSERT_NOT_REACHED();
923 return RTCIceTransport::TransportState::New;
926 void MediaEndpointPeerConnection::iceTransportStateChanged(const String& mid, MediaEndpoint::IceTransportState mediaEndpointIceTransportState)
928 ASSERT(isMainThread());
930 RTCRtpTransceiver* transceiver = matchTransceiverByMid(m_client->getTransceivers(), mid);
933 RTCIceTransport::TransportState transportState = static_cast<RTCIceTransport::TransportState>(mediaEndpointIceTransportState);
934 transceiver->iceTransport().setTransportState(transportState);
936 // Determine if the script needs to be notified.
937 Vector<RTCIceTransport::TransportState> transportStates;
938 for (auto& transceiver : m_client->getTransceivers())
939 transportStates.append(transceiver->iceTransport().transportState());
941 RTCIceTransport::TransportState derivedState = deriveAggregatedIceConnectionState(transportStates);
942 m_client->updateIceConnectionState(static_cast<IceConnectionState>(derivedState));
945 } // namespace WebCore
947 #endif // ENABLE(WEB_RTC)