summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/jsapi
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:27 +0000
commit40a355a42d4a9444dc753c04c6608dade2f06a23 (patch)
tree871fc667d2de662f171103ce5ec067014ef85e61 /dom/media/webrtc/jsapi
parentAdding upstream version 124.0.1. (diff)
downloadfirefox-40a355a42d4a9444dc753c04c6608dade2f06a23.tar.xz
firefox-40a355a42d4a9444dc753c04c6608dade2f06a23.zip
Adding upstream version 125.0.1.upstream/125.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/media/webrtc/jsapi')
-rw-r--r--dom/media/webrtc/jsapi/MediaTransportHandler.cpp62
-rw-r--r--dom/media/webrtc/jsapi/MediaTransportHandler.h15
-rw-r--r--dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp10
-rw-r--r--dom/media/webrtc/jsapi/MediaTransportParent.cpp14
-rw-r--r--dom/media/webrtc/jsapi/PeerConnectionImpl.cpp562
-rw-r--r--dom/media/webrtc/jsapi/PeerConnectionImpl.h42
-rw-r--r--dom/media/webrtc/jsapi/RTCDtlsTransport.cpp7
-rw-r--r--dom/media/webrtc/jsapi/RTCDtlsTransport.h3
-rw-r--r--dom/media/webrtc/jsapi/RTCIceTransport.cpp60
-rw-r--r--dom/media/webrtc/jsapi/RTCIceTransport.h53
-rw-r--r--dom/media/webrtc/jsapi/RTCRtpReceiver.cpp4
-rw-r--r--dom/media/webrtc/jsapi/RTCRtpSender.cpp1
-rw-r--r--dom/media/webrtc/jsapi/RTCRtpTransceiver.cpp33
-rw-r--r--dom/media/webrtc/jsapi/RTCRtpTransceiver.h3
-rw-r--r--dom/media/webrtc/jsapi/moz.build2
15 files changed, 643 insertions, 228 deletions
diff --git a/dom/media/webrtc/jsapi/MediaTransportHandler.cpp b/dom/media/webrtc/jsapi/MediaTransportHandler.cpp
index 3ee95f36f6..cf95ef41d6 100644
--- a/dom/media/webrtc/jsapi/MediaTransportHandler.cpp
+++ b/dom/media/webrtc/jsapi/MediaTransportHandler.cpp
@@ -156,9 +156,9 @@ class MediaTransportHandlerSTS : public MediaTransportHandler,
using MediaTransportHandler::OnRtcpStateChange;
using MediaTransportHandler::OnStateChange;
- void OnGatheringStateChange(NrIceCtx* aIceCtx,
- NrIceCtx::GatheringState aState);
- void OnConnectionStateChange(NrIceCtx* aIceCtx,
+ void OnGatheringStateChange(const std::string& aTransportId,
+ NrIceMediaStream::GatheringState aState);
+ void OnConnectionStateChange(NrIceMediaStream* aIceStream,
NrIceCtx::ConnectionState aState);
void OnCandidateFound(NrIceMediaStream* aStream,
const std::string& aCandidate,
@@ -589,8 +589,6 @@ void MediaTransportHandlerSTS::CreateIceCtx(const std::string& aName) {
__func__);
}
- mIceCtx->SignalGatheringStateChange.connect(
- this, &MediaTransportHandlerSTS::OnGatheringStateChange);
mIceCtx->SignalConnectionStateChange.connect(
this, &MediaTransportHandlerSTS::OnConnectionStateChange);
@@ -784,6 +782,8 @@ void MediaTransportHandlerSTS::EnsureProvisionalTransport(
stream->SignalCandidate.connect(
this, &MediaTransportHandlerSTS::OnCandidateFound);
+ stream->SignalGatheringStateChange.connect(
+ this, &MediaTransportHandlerSTS::OnGatheringStateChange);
}
// Begins an ICE restart if this stream has a different ufrag/pwd
@@ -1181,31 +1181,31 @@ void MediaTransportHandler::OnAlpnNegotiated(const std::string& aAlpn) {
}
void MediaTransportHandler::OnGatheringStateChange(
- dom::RTCIceGatheringState aState) {
+ const std::string& aTransportId, dom::RTCIceGathererState aState) {
if (mCallbackThread && !mCallbackThread->IsOnCurrentThread()) {
mCallbackThread->Dispatch(
// This is being called from sigslot, which does not hold a strong ref.
WrapRunnable(this, &MediaTransportHandler::OnGatheringStateChange,
- aState),
+ aTransportId, aState),
NS_DISPATCH_NORMAL);
return;
}
- SignalGatheringStateChange(aState);
+ SignalGatheringStateChange(aTransportId, aState);
}
void MediaTransportHandler::OnConnectionStateChange(
- dom::RTCIceConnectionState aState) {
+ const std::string& aTransportId, dom::RTCIceTransportState aState) {
if (mCallbackThread && !mCallbackThread->IsOnCurrentThread()) {
mCallbackThread->Dispatch(
// This is being called from sigslot, which does not hold a strong ref.
WrapRunnable(this, &MediaTransportHandler::OnConnectionStateChange,
- aState),
+ aTransportId, aState),
NS_DISPATCH_NORMAL);
return;
}
- SignalConnectionStateChange(aState);
+ SignalConnectionStateChange(aTransportId, aState);
}
void MediaTransportHandler::OnPacketReceived(const std::string& aTransportId,
@@ -1583,48 +1583,48 @@ RefPtr<TransportFlow> MediaTransportHandlerSTS::CreateTransportFlow(
return flow;
}
-static mozilla::dom::RTCIceGatheringState toDomIceGatheringState(
- NrIceCtx::GatheringState aState) {
+static mozilla::dom::RTCIceGathererState toDomIceGathererState(
+ NrIceMediaStream::GatheringState aState) {
switch (aState) {
- case NrIceCtx::ICE_CTX_GATHER_INIT:
- return dom::RTCIceGatheringState::New;
- case NrIceCtx::ICE_CTX_GATHER_STARTED:
- return dom::RTCIceGatheringState::Gathering;
- case NrIceCtx::ICE_CTX_GATHER_COMPLETE:
- return dom::RTCIceGatheringState::Complete;
+ case NrIceMediaStream::ICE_STREAM_GATHER_INIT:
+ return dom::RTCIceGathererState::New;
+ case NrIceMediaStream::ICE_STREAM_GATHER_STARTED:
+ return dom::RTCIceGathererState::Gathering;
+ case NrIceMediaStream::ICE_STREAM_GATHER_COMPLETE:
+ return dom::RTCIceGathererState::Complete;
}
MOZ_CRASH();
}
void MediaTransportHandlerSTS::OnGatheringStateChange(
- NrIceCtx* aIceCtx, NrIceCtx::GatheringState aState) {
- OnGatheringStateChange(toDomIceGatheringState(aState));
+ const std::string& aTransportId, NrIceMediaStream::GatheringState aState) {
+ OnGatheringStateChange(aTransportId, toDomIceGathererState(aState));
}
-static mozilla::dom::RTCIceConnectionState toDomIceConnectionState(
+static mozilla::dom::RTCIceTransportState toDomIceTransportState(
NrIceCtx::ConnectionState aState) {
switch (aState) {
case NrIceCtx::ICE_CTX_INIT:
- return dom::RTCIceConnectionState::New;
+ return dom::RTCIceTransportState::New;
case NrIceCtx::ICE_CTX_CHECKING:
- return dom::RTCIceConnectionState::Checking;
+ return dom::RTCIceTransportState::Checking;
case NrIceCtx::ICE_CTX_CONNECTED:
- return dom::RTCIceConnectionState::Connected;
+ return dom::RTCIceTransportState::Connected;
case NrIceCtx::ICE_CTX_COMPLETED:
- return dom::RTCIceConnectionState::Completed;
+ return dom::RTCIceTransportState::Completed;
case NrIceCtx::ICE_CTX_FAILED:
- return dom::RTCIceConnectionState::Failed;
+ return dom::RTCIceTransportState::Failed;
case NrIceCtx::ICE_CTX_DISCONNECTED:
- return dom::RTCIceConnectionState::Disconnected;
+ return dom::RTCIceTransportState::Disconnected;
case NrIceCtx::ICE_CTX_CLOSED:
- return dom::RTCIceConnectionState::Closed;
+ return dom::RTCIceTransportState::Closed;
}
MOZ_CRASH();
}
void MediaTransportHandlerSTS::OnConnectionStateChange(
- NrIceCtx* aIceCtx, NrIceCtx::ConnectionState aState) {
- OnConnectionStateChange(toDomIceConnectionState(aState));
+ NrIceMediaStream* aIceStream, NrIceCtx::ConnectionState aState) {
+ OnConnectionStateChange(aIceStream->GetId(), toDomIceTransportState(aState));
}
// The stuff below here will eventually go into the MediaTransportChild class
diff --git a/dom/media/webrtc/jsapi/MediaTransportHandler.h b/dom/media/webrtc/jsapi/MediaTransportHandler.h
index a776cb6fd7..100eff019e 100644
--- a/dom/media/webrtc/jsapi/MediaTransportHandler.h
+++ b/dom/media/webrtc/jsapi/MediaTransportHandler.h
@@ -12,7 +12,8 @@
#include "transport/dtlsidentity.h" // For DtlsDigest
#include "mozilla/dom/RTCPeerConnectionBinding.h"
#include "mozilla/dom/RTCConfigurationBinding.h"
-#include "transport/nricectx.h" // Need some enums
+#include "mozilla/dom/RTCIceTransportBinding.h" // RTCIceTransportState
+#include "transport/nricectx.h" // Need some enums
#include "common/CandidateInfo.h"
#include "transport/nr_socket_proxy_config.h"
#include "RTCStatsReport.h"
@@ -122,8 +123,10 @@ class MediaTransportHandler {
sigslot::signal2<const std::string&, const CandidateInfo&> SignalCandidate;
sigslot::signal2<const std::string&, bool> SignalAlpnNegotiated;
- sigslot::signal1<dom::RTCIceGatheringState> SignalGatheringStateChange;
- sigslot::signal1<dom::RTCIceConnectionState> SignalConnectionStateChange;
+ sigslot::signal2<const std::string&, dom::RTCIceGathererState>
+ SignalGatheringStateChange;
+ sigslot::signal2<const std::string&, dom::RTCIceTransportState>
+ SignalConnectionStateChange;
sigslot::signal2<const std::string&, const MediaPacket&> SignalPacketReceived;
sigslot::signal2<const std::string&, const MediaPacket&>
@@ -142,8 +145,10 @@ class MediaTransportHandler {
void OnCandidate(const std::string& aTransportId,
const CandidateInfo& aCandidateInfo);
void OnAlpnNegotiated(const std::string& aAlpn);
- void OnGatheringStateChange(dom::RTCIceGatheringState aState);
- void OnConnectionStateChange(dom::RTCIceConnectionState aState);
+ void OnGatheringStateChange(const std::string& aTransportId,
+ dom::RTCIceGathererState aState);
+ void OnConnectionStateChange(const std::string& aTransportId,
+ dom::RTCIceTransportState aState);
void OnPacketReceived(const std::string& aTransportId,
const MediaPacket& aPacket);
void OnEncryptedSending(const std::string& aTransportId,
diff --git a/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp b/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp
index 847e9fd3de..4d13ae0ac0 100644
--- a/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp
+++ b/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp
@@ -406,21 +406,21 @@ mozilla::ipc::IPCResult MediaTransportChild::RecvOnAlpnNegotiated(
}
mozilla::ipc::IPCResult MediaTransportChild::RecvOnGatheringStateChange(
- const int& state) {
+ const string& transportId, const int& state) {
MutexAutoLock lock(mMutex);
if (mUser) {
- mUser->OnGatheringStateChange(
- static_cast<dom::RTCIceGatheringState>(state));
+ mUser->OnGatheringStateChange(transportId,
+ static_cast<dom::RTCIceGathererState>(state));
}
return ipc::IPCResult::Ok();
}
mozilla::ipc::IPCResult MediaTransportChild::RecvOnConnectionStateChange(
- const int& state) {
+ const string& transportId, const int& state) {
MutexAutoLock lock(mMutex);
if (mUser) {
mUser->OnConnectionStateChange(
- static_cast<dom::RTCIceConnectionState>(state));
+ transportId, static_cast<dom::RTCIceTransportState>(state));
}
return ipc::IPCResult::Ok();
}
diff --git a/dom/media/webrtc/jsapi/MediaTransportParent.cpp b/dom/media/webrtc/jsapi/MediaTransportParent.cpp
index 31d0b9f30f..4bbd75b41c 100644
--- a/dom/media/webrtc/jsapi/MediaTransportParent.cpp
+++ b/dom/media/webrtc/jsapi/MediaTransportParent.cpp
@@ -49,14 +49,16 @@ class MediaTransportParent::Impl : public sigslot::has_slots<> {
NS_ENSURE_TRUE_VOID(mParent->SendOnAlpnNegotiated(aAlpn));
}
- void OnGatheringStateChange(dom::RTCIceGatheringState aState) {
- NS_ENSURE_TRUE_VOID(
- mParent->SendOnGatheringStateChange(static_cast<int>(aState)));
+ void OnGatheringStateChange(const std::string& aTransportId,
+ dom::RTCIceGathererState aState) {
+ NS_ENSURE_TRUE_VOID(mParent->SendOnGatheringStateChange(
+ aTransportId, static_cast<int>(aState)));
}
- void OnConnectionStateChange(dom::RTCIceConnectionState aState) {
- NS_ENSURE_TRUE_VOID(
- mParent->SendOnConnectionStateChange(static_cast<int>(aState)));
+ void OnConnectionStateChange(const std::string& aTransportId,
+ dom::RTCIceTransportState aState) {
+ NS_ENSURE_TRUE_VOID(mParent->SendOnConnectionStateChange(
+ aTransportId, static_cast<int>(aState)));
}
void OnPacketReceived(const std::string& aTransportId,
diff --git a/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp b/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp
index 985100153a..9afa7e5dd2 100644
--- a/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp
+++ b/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp
@@ -85,6 +85,7 @@
#include "mozilla/dom/RTCCertificate.h"
#include "mozilla/dom/RTCSctpTransportBinding.h" // RTCSctpTransportState
#include "mozilla/dom/RTCDtlsTransportBinding.h" // RTCDtlsTransportState
+#include "mozilla/dom/RTCIceTransportBinding.h" // RTCIceTransportState
#include "mozilla/dom/RTCRtpReceiverBinding.h"
#include "mozilla/dom/RTCRtpSenderBinding.h"
#include "mozilla/dom/RTCStatsReportBinding.h"
@@ -249,19 +250,41 @@ void PeerConnectionAutoTimer::UnregisterConnection(bool aContainedAV) {
bool PeerConnectionAutoTimer::IsStopped() { return mRefCnt == 0; }
+// There is not presently an implementation of these for nsTHashMap :(
+inline void ImplCycleCollectionUnlink(
+ PeerConnectionImpl::RTCDtlsTransportMap& aMap) {
+ for (auto& tableEntry : aMap) {
+ ImplCycleCollectionUnlink(*tableEntry.GetModifiableData());
+ }
+ aMap.Clear();
+}
+
+inline void ImplCycleCollectionTraverse(
+ nsCycleCollectionTraversalCallback& aCallback,
+ PeerConnectionImpl::RTCDtlsTransportMap& aMap, const char* aName,
+ uint32_t aFlags = 0) {
+ for (auto& tableEntry : aMap) {
+ ImplCycleCollectionTraverse(aCallback, *tableEntry.GetModifiableData(),
+ aName, aFlags);
+ }
+}
+
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(PeerConnectionImpl)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PeerConnectionImpl)
tmp->Close();
tmp->BreakCycles();
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mPCObserver, mWindow, mCertificate,
- mSTSThread, mReceiveStreams, mOperations,
- mSctpTransport, mKungFuDeathGrip)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(
+ mPCObserver, mWindow, mCertificate, mSTSThread, mReceiveStreams,
+ mOperations, mTransportIdToRTCDtlsTransport, mSctpTransport,
+ mLastStableSctpTransport, mLastStableSctpDtlsTransport, mKungFuDeathGrip)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(PeerConnectionImpl)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
mPCObserver, mWindow, mCertificate, mSTSThread, mReceiveStreams,
- mOperations, mTransceivers, mSctpTransport, mKungFuDeathGrip)
+ mOperations, mTransceivers, mTransportIdToRTCDtlsTransport,
+ mSctpTransport, mLastStableSctpTransport, mLastStableSctpDtlsTransport,
+ mKungFuDeathGrip)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(PeerConnectionImpl)
@@ -849,6 +872,7 @@ nsresult PeerConnectionImpl::GetDatachannelParameters(
if (!datachannelTransceiver ||
!datachannelTransceiver->mTransport.mComponents ||
+ !datachannelTransceiver->mTransport.mDtls ||
!datachannelTransceiver->mSendTrack.GetNegotiatedDetails()) {
return NS_ERROR_FAILURE;
}
@@ -1061,7 +1085,7 @@ bool PeerConnectionImpl::CreatedSender(const dom::RTCRtpSender& aSender) const {
return aSender.IsMyPc(this);
}
-nsresult PeerConnectionImpl::InitializeDataChannel() {
+nsresult PeerConnectionImpl::MaybeInitializeDataChannel() {
PC_AUTO_ENTER_API_CALL(false);
CSFLogDebug(LOGTAG, "%s", __FUNCTION__);
@@ -1440,6 +1464,16 @@ void PeerConnectionImpl::UpdateNegotiationNeeded() {
}));
}
+RefPtr<dom::RTCRtpTransceiver> PeerConnectionImpl::GetTransceiver(
+ const std::string& aTransceiverId) {
+ for (const auto& transceiver : mTransceivers) {
+ if (transceiver->GetJsepTransceiverId() == aTransceiverId) {
+ return transceiver;
+ }
+ }
+ return nullptr;
+}
+
void PeerConnectionImpl::NotifyDataChannel(
already_AddRefed<DataChannel> aChannel) {
PC_AUTO_ENTER_API_CALL_NO_CHECK();
@@ -1637,7 +1671,6 @@ JsepSdpType ToJsepSdpType(dom::RTCSdpType aType) {
return kJsepSdpAnswer;
case dom::RTCSdpType::Rollback:
return kJsepSdpRollback;
- case dom::RTCSdpType::EndGuard_:;
}
MOZ_CRASH("Nonexistent dom::RTCSdpType");
@@ -1989,10 +2022,14 @@ nsresult PeerConnectionImpl::OnAlpnNegotiated(bool aPrivacyRequested) {
void PeerConnectionImpl::OnDtlsStateChange(const std::string& aTransportId,
TransportLayer::State aState) {
- auto it = mTransportIdToRTCDtlsTransport.find(aTransportId);
- if (it != mTransportIdToRTCDtlsTransport.end()) {
- it->second->UpdateState(aState);
+ nsCString key(aTransportId.data(), aTransportId.size());
+ RefPtr<RTCDtlsTransport> dtlsTransport =
+ mTransportIdToRTCDtlsTransport.Get(key);
+ if (!dtlsTransport) {
+ return;
}
+
+ dtlsTransport->UpdateState(aState);
// Whenever the state of an RTCDtlsTransport changes or when the [[IsClosed]]
// slot turns true, the user agent MUST update the connection state by
// queueing a task that runs the following steps:
@@ -2024,9 +2061,9 @@ RTCPeerConnectionState PeerConnectionImpl::GetNewConnectionState() const {
// Would use a bitset, but that requires lots of static_cast<size_t>
// Oh well.
std::set<RTCDtlsTransportState> statesFound;
- for (const auto& [id, dtlsTransport] : mTransportIdToRTCDtlsTransport) {
- Unused << id;
- statesFound.insert(dtlsTransport->State());
+ std::set<RefPtr<RTCDtlsTransport>> transports(GetActiveTransports());
+ for (const auto& transport : transports) {
+ statesFound.insert(transport->State());
}
// failed The previous state doesn't apply, and either
@@ -2075,9 +2112,9 @@ RTCPeerConnectionState PeerConnectionImpl::GetNewConnectionState() const {
bool PeerConnectionImpl::UpdateConnectionState() {
auto newState = GetNewConnectionState();
if (newState != mConnectionState) {
- CSFLogDebug(LOGTAG, "%s: %d -> %d (%p)", __FUNCTION__,
- static_cast<int>(mConnectionState), static_cast<int>(newState),
- this);
+ CSFLogInfo(LOGTAG, "%s: %d -> %d (%p)", __FUNCTION__,
+ static_cast<int>(mConnectionState), static_cast<int>(newState),
+ this);
mConnectionState = newState;
if (mConnectionState != RTCPeerConnectionState::Closed) {
return true;
@@ -2569,7 +2606,7 @@ PeerConnectionImpl::Close() {
transceiver->Close();
}
- mTransportIdToRTCDtlsTransport.clear();
+ mTransportIdToRTCDtlsTransport.Clear();
mQueuedIceCtxOperations.clear();
@@ -2964,18 +3001,25 @@ void PeerConnectionImpl::DoSetDescriptionSuccessPostProcessing(
InvalidateLastReturnedParameters();
}
+ if (aSdpType == dom::RTCSdpType::Offer &&
+ mSignalingState == RTCSignalingState::Stable) {
+ // If description is of type "offer" and
+ // connection.[[SignalingState]] is "stable" then for each
+ // transceiver in connection's set of transceivers, run the following
+ // steps:
+ SaveStateForRollback();
+ }
+
// Section 4.4.1.5 Set the RTCSessionDescription:
if (aSdpType == dom::RTCSdpType::Rollback) {
// - step 4.5.10, type is rollback
- RollbackRTCDtlsTransports();
+ RestoreStateForRollback();
} else if (!(aRemote && aSdpType == dom::RTCSdpType::Offer)) {
// - step 4.5.9 type is not rollback
// - step 4.5.9.1 when remote is false
// - step 4.5.9.2.13 when remote is true, type answer or pranswer
// More simply: not rollback, and not for remote offers.
- bool markAsStable = aSdpType == dom::RTCSdpType::Offer &&
- mSignalingState == RTCSignalingState::Stable;
- UpdateRTCDtlsTransports(markAsStable);
+ UpdateRTCDtlsTransports();
}
// Did we just apply a local description?
@@ -2992,11 +3036,6 @@ void PeerConnectionImpl::DoSetDescriptionSuccessPostProcessing(
}
if (mJsepSession->GetState() == kJsepStateStable) {
- if (aSdpType != dom::RTCSdpType::Rollback) {
- // We need this initted for UpdateTransports
- InitializeDataChannel();
- }
-
// If we're rolling back a local offer, we might need to remove some
// transports, and stomp some MediaPipeline setup, but nothing further
// needs to be done.
@@ -3071,6 +3110,10 @@ void PeerConnectionImpl::DoSetDescriptionSuccessPostProcessing(
// Spec does not actually tell us to do this, but that is probably a
// spec bug.
// https://github.com/w3c/webrtc-pc/issues/2817
+ bool gatheringStateChanged = UpdateIceGatheringState();
+
+ bool iceConnectionStateChanged = UpdateIceConnectionState();
+
bool connectionStateChanged = UpdateConnectionState();
// This only gets populated for remote descriptions
@@ -3104,6 +3147,16 @@ void PeerConnectionImpl::DoSetDescriptionSuccessPostProcessing(
pcObserver->OnStateChange(PCObserverStateType::SignalingState, jrv);
}
+ if (gatheringStateChanged) {
+ pcObserver->OnStateChange(PCObserverStateType::IceGatheringState,
+ jrv);
+ }
+
+ if (iceConnectionStateChanged) {
+ pcObserver->OnStateChange(PCObserverStateType::IceConnectionState,
+ jrv);
+ }
+
if (connectionStateChanged) {
pcObserver->OnStateChange(PCObserverStateType::ConnectionState, jrv);
}
@@ -3290,61 +3343,162 @@ void PeerConnectionImpl::SendLocalIceCandidateToContent(
}
void PeerConnectionImpl::IceConnectionStateChange(
- dom::RTCIceConnectionState domState) {
+ const std::string& aTransportId, dom::RTCIceTransportState domState) {
+ // If connection.[[IsClosed]] is true, abort these steps.
PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
- CSFLogDebug(LOGTAG, "%s: %d -> %d", __FUNCTION__,
- static_cast<int>(mIceConnectionState),
- static_cast<int>(domState));
+ CSFLogDebug(LOGTAG, "IceConnectionStateChange: %s %d (%p)",
+ aTransportId.c_str(), static_cast<int>(domState), this);
- if (domState == mIceConnectionState) {
- // no work to be done since the states are the same.
- // this can happen during ICE rollback situations.
+ // Let transport be the RTCIceTransport whose state is changing.
+ nsCString key(aTransportId.data(), aTransportId.size());
+ RefPtr<RTCDtlsTransport> dtlsTransport =
+ mTransportIdToRTCDtlsTransport.Get(key);
+ if (!dtlsTransport) {
return;
}
+ RefPtr<RTCIceTransport> transport = dtlsTransport->IceTransport();
- mIceConnectionState = domState;
+ if (domState == RTCIceTransportState::Closed) {
+ mTransportIdToRTCDtlsTransport.Remove(key);
+ }
- // Would be nice if we had a means of converting one of these dom enums
- // to a string that wasn't almost as much text as this switch statement...
- switch (mIceConnectionState) {
- case RTCIceConnectionState::New:
- STAMP_TIMECARD(mTimeCard, "Ice state: new");
- break;
- case RTCIceConnectionState::Checking:
- // For telemetry
- mIceStartTime = TimeStamp::Now();
- STAMP_TIMECARD(mTimeCard, "Ice state: checking");
- break;
- case RTCIceConnectionState::Connected:
- STAMP_TIMECARD(mTimeCard, "Ice state: connected");
- StartCallTelem();
- break;
- case RTCIceConnectionState::Completed:
- STAMP_TIMECARD(mTimeCard, "Ice state: completed");
- break;
- case RTCIceConnectionState::Failed:
- STAMP_TIMECARD(mTimeCard, "Ice state: failed");
- break;
- case RTCIceConnectionState::Disconnected:
- STAMP_TIMECARD(mTimeCard, "Ice state: disconnected");
- break;
- case RTCIceConnectionState::Closed:
- STAMP_TIMECARD(mTimeCard, "Ice state: closed");
- break;
- default:
- MOZ_ASSERT_UNREACHABLE("Unexpected mIceConnectionState!");
+ // Let selectedCandidatePairChanged be false.
+ // TODO(bug 1307994)
+
+ // Let transportIceConnectionStateChanged be false.
+ bool transportIceConnectionStateChanged = false;
+
+ // Let connectionIceConnectionStateChanged be false.
+ bool connectionIceConnectionStateChanged = false;
+
+ // Let connectionStateChanged be false.
+ bool connectionStateChanged = false;
+
+ if (transport->State() == domState) {
+ return;
+ }
+
+ // If transport's RTCIceTransportState was changed, run the following steps:
+
+ // Set transport.[[IceTransportState]] to the new indicated
+ // RTCIceTransportState.
+ transport->SetState(domState);
+
+ // Set transportIceConnectionStateChanged to true.
+ transportIceConnectionStateChanged = true;
+
+ // Set connection.[[IceConnectionState]] to the value of deriving a new state
+ // value as described by the RTCIceConnectionState enum.
+ if (UpdateIceConnectionState()) {
+ // If connection.[[IceConnectionState]] changed in the previous step, set
+ // connectionIceConnectionStateChanged to true.
+ connectionIceConnectionStateChanged = true;
+ }
+
+ // Set connection.[[ConnectionState]] to the value of deriving a new state
+ // value as described by the RTCPeerConnectionState enum.
+ if (UpdateConnectionState()) {
+ // If connection.[[ConnectionState]] changed in the previous step, set
+ // connectionStateChanged to true.
+ connectionStateChanged = true;
+ }
+
+ // If selectedCandidatePairChanged is true, fire an event named
+ // selectedcandidatepairchange at transport.
+ // TODO(bug 1307994)
+
+ // If transportIceConnectionStateChanged is true, fire an event named
+ // statechange at transport.
+ if (transportIceConnectionStateChanged) {
+ transport->FireStateChangeEvent();
}
- bool connectionStateChanged = UpdateConnectionState();
WrappableJSErrorResult rv;
RefPtr<PeerConnectionObserver> pcObserver(mPCObserver);
- pcObserver->OnStateChange(PCObserverStateType::IceConnectionState, rv);
+
+ // If connectionIceConnectionStateChanged is true, fire an event named
+ // iceconnectionstatechange at connection.
+ if (connectionIceConnectionStateChanged) {
+ pcObserver->OnStateChange(PCObserverStateType::IceConnectionState, rv);
+ }
+
+ // If connectionStateChanged is true, fire an event named
+ // connectionstatechange at connection.
if (connectionStateChanged) {
pcObserver->OnStateChange(PCObserverStateType::ConnectionState, rv);
}
}
+RTCIceConnectionState PeerConnectionImpl::GetNewIceConnectionState() const {
+ // closed The RTCPeerConnection object's [[IsClosed]] slot is true.
+ if (IsClosed()) {
+ return RTCIceConnectionState::Closed;
+ }
+
+ // Would use a bitset, but that requires lots of static_cast<size_t>
+ // Oh well.
+ std::set<RTCIceTransportState> statesFound;
+ std::set<RefPtr<RTCDtlsTransport>> transports(GetActiveTransports());
+ for (const auto& transport : transports) {
+ RefPtr<dom::RTCIceTransport> iceTransport = transport->IceTransport();
+ CSFLogWarn(LOGTAG, "GetNewIceConnectionState: %p %d", iceTransport.get(),
+ static_cast<int>(iceTransport->State()));
+ statesFound.insert(iceTransport->State());
+ }
+
+ // failed None of the previous states apply and any RTCIceTransports are
+ // in the "failed" state.
+ if (statesFound.count(RTCIceTransportState::Failed)) {
+ return RTCIceConnectionState::Failed;
+ }
+
+ // disconnected None of the previous states apply and any
+ // RTCIceTransports are in the "disconnected" state.
+ if (statesFound.count(RTCIceTransportState::Disconnected)) {
+ return RTCIceConnectionState::Disconnected;
+ }
+
+ // new None of the previous states apply and all RTCIceTransports are
+ // in the "new" or "closed" state, or there are no transports.
+ if (!statesFound.count(RTCIceTransportState::Checking) &&
+ !statesFound.count(RTCIceTransportState::Completed) &&
+ !statesFound.count(RTCIceTransportState::Connected)) {
+ return RTCIceConnectionState::New;
+ }
+
+ // checking None of the previous states apply and any RTCIceTransports are
+ // in the "new" or "checking" state.
+ if (statesFound.count(RTCIceTransportState::New) ||
+ statesFound.count(RTCIceTransportState::Checking)) {
+ return RTCIceConnectionState::Checking;
+ }
+
+ // completed None of the previous states apply and all RTCIceTransports are
+ // in the "completed" or "closed" state.
+ if (!statesFound.count(RTCIceTransportState::Connected)) {
+ return RTCIceConnectionState::Completed;
+ }
+
+ // connected None of the previous states apply.
+ return RTCIceConnectionState::Connected;
+}
+
+bool PeerConnectionImpl::UpdateIceConnectionState() {
+ auto newState = GetNewIceConnectionState();
+ if (newState != mIceConnectionState) {
+ CSFLogInfo(LOGTAG, "%s: %d -> %d (%p)", __FUNCTION__,
+ static_cast<int>(mIceConnectionState),
+ static_cast<int>(newState), this);
+ mIceConnectionState = newState;
+ if (mIceConnectionState != RTCIceConnectionState::Closed) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void PeerConnectionImpl::OnCandidateFound(const std::string& aTransportId,
const CandidateInfo& aCandidateInfo) {
if (mStunAddrsRequest && !aCandidateInfo.mMDNSAddress.empty()) {
@@ -3378,18 +3532,82 @@ void PeerConnectionImpl::OnCandidateFound(const std::string& aTransportId,
}
void PeerConnectionImpl::IceGatheringStateChange(
- dom::RTCIceGatheringState state) {
+ const std::string& aTransportId, dom::RTCIceGathererState state) {
+ // If connection.[[IsClosed]] is true, abort these steps.
PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
- CSFLogDebug(LOGTAG, "%s %d", __FUNCTION__, static_cast<int>(state));
- if (mIceGatheringState == state) {
+ CSFLogWarn(LOGTAG, "IceGatheringStateChange: %s %d (%p)",
+ aTransportId.c_str(), static_cast<int>(state), this);
+
+ // Let transport be the RTCIceTransport for which candidate gathering
+ // began/finished.
+ nsCString key(aTransportId.data(), aTransportId.size());
+ RefPtr<RTCDtlsTransport> dtlsTransport =
+ mTransportIdToRTCDtlsTransport.Get(key);
+ if (!dtlsTransport) {
+ return;
+ }
+ RefPtr<RTCIceTransport> transport = dtlsTransport->IceTransport();
+
+ if (transport->GatheringState() == state) {
return;
}
- mIceGatheringState = state;
+ // Set transport.[[IceGathererState]] to gathering.
+ // or
+ // Set transport.[[IceGathererState]] to complete.
+ transport->SetGatheringState(state);
+
+ // Set connection.[[IceGatheringState]] to the value of deriving a new state
+ // value as described by the RTCIceGatheringState enum.
+ //
+ // Let connectionIceGatheringStateChanged be true if
+ // connection.[[IceGatheringState]] changed in the previous step, otherwise
+ // false.
+ bool gatheringStateChanged = UpdateIceGatheringState();
+
+ // Do not read or modify state beyond this point.
+
+ // Fire an event named gatheringstatechange at transport.
+ transport->FireGatheringStateChangeEvent();
+
+ // If connectionIceGatheringStateChanged is true, fire an event named
+ // icegatheringstatechange at connection.
+ if (gatheringStateChanged) {
+ // NOTE: If we're in the "complete" case, our JS code will fire a null
+ // icecandidate event after firing the icegatheringstatechange event.
+ // Fire an event named icecandidate using the RTCPeerConnectionIceEvent
+ // interface with the candidate attribute set to null at connection.
+ JSErrorResult rv;
+ mPCObserver->OnStateChange(PCObserverStateType::IceGatheringState, rv);
+ }
+}
+
+bool PeerConnectionImpl::UpdateIceGatheringState() {
+ // If connection.[[IsClosed]] is true, abort these steps.
+ if (IsClosed()) {
+ return false;
+ }
+
+ // Let newState be the value of deriving a new state value as
+ // described by the RTCIceGatheringState enum.
+ auto newState = GetNewIceGatheringState();
+
+ // If connection.[[IceGatheringState]] is equal to newState, abort
+ // these steps.
+ if (newState == mIceGatheringState) {
+ return false;
+ }
+
+ CSFLogInfo(LOGTAG, "UpdateIceGatheringState: %d -> %d (%p)",
+ static_cast<int>(mIceGatheringState), static_cast<int>(newState),
+ this);
+ // Set connection.[[IceGatheringState]] to newState.
+ mIceGatheringState = newState;
- // Would be nice if we had a means of converting one of these dom enums
- // to a string that wasn't almost as much text as this switch statement...
+ // Would be nice if we had a means of converting one of these dom
+ // enums to a string that wasn't almost as much text as this switch
+ // statement...
switch (mIceGatheringState) {
case RTCIceGatheringState::New:
STAMP_TIMECARD(mTimeCard, "Ice gathering state: new");
@@ -3404,8 +3622,42 @@ void PeerConnectionImpl::IceGatheringStateChange(
MOZ_ASSERT_UNREACHABLE("Unexpected mIceGatheringState!");
}
- JSErrorResult rv;
- mPCObserver->OnStateChange(PCObserverStateType::IceGatheringState, rv);
+ return true;
+}
+
+RTCIceGatheringState PeerConnectionImpl::GetNewIceGatheringState() const {
+ // new Any of the RTCIceTransports are in the "new" gathering state
+ // and none of the transports are in the "gathering" state, or there are no
+ // transports.
+
+ // NOTE! This derives the RTCIce**Gathering**State from the individual
+ // RTCIce**Gatherer**State of the transports. These are different enums.
+ // But they have exactly the same values, in the same order.
+ // ¯\_(ツ)_/¯
+ bool foundComplete = false;
+ std::set<RefPtr<RTCDtlsTransport>> transports(GetActiveTransports());
+ for (const auto& transport : transports) {
+ RefPtr<dom::RTCIceTransport> iceTransport = transport->IceTransport();
+ switch (iceTransport->GatheringState()) {
+ case RTCIceGathererState::New:
+ break;
+ case RTCIceGathererState::Gathering:
+ // gathering Any of the RTCIceTransports are in the "gathering"
+ // state.
+ return RTCIceGatheringState::Gathering;
+ case RTCIceGathererState::Complete:
+ foundComplete = true;
+ break;
+ }
+ }
+
+ if (!foundComplete) {
+ return RTCIceGatheringState::New;
+ }
+
+ // This could change depending on the outcome in
+ // https://github.com/w3c/webrtc-pc/issues/2914
+ return RTCIceGatheringState::Complete;
}
void PeerConnectionImpl::UpdateDefaultCandidate(
@@ -3878,11 +4130,8 @@ void PeerConnectionImpl::StunAddrsHandler::OnStunAddrsAvailable(
pcw.impl()->mStunAddrs = addrs.Clone();
pcw.impl()->mLocalAddrsRequestState = STUN_ADDR_REQUEST_COMPLETE;
pcw.impl()->FlushIceCtxOperationQueueIfReady();
- // If parent process returns 0 STUN addresses, change ICE connection
- // state to failed.
- if (!pcw.impl()->mStunAddrs.Length()) {
- pcw.impl()->IceConnectionStateChange(dom::RTCIceConnectionState::Failed);
- }
+ // If this fails, ICE cannot succeed, but we need to still go through the
+ // motions.
}
void PeerConnectionImpl::InitLocalAddrs() {
@@ -3952,109 +4201,120 @@ void PeerConnectionImpl::EnsureTransports(const JsepSession& aSession) {
GatherIfReady();
}
-void PeerConnectionImpl::UpdateRTCDtlsTransports(bool aMarkAsStable) {
+void PeerConnectionImpl::UpdateRTCDtlsTransports() {
+ // We use mDataConnection below, make sure it is initted if necessary
+ MaybeInitializeDataChannel();
+
+ // Make sure that the SCTP transport is unset if we do not see a DataChannel.
+ // We'll restore this if we do see a DataChannel.
+ RefPtr<dom::RTCSctpTransport> oldSctp = mSctpTransport.forget();
+
mJsepSession->ForEachTransceiver(
- [this, self = RefPtr<PeerConnectionImpl>(this)](
- const JsepTransceiver& jsepTransceiver) {
+ [this, self = RefPtr<PeerConnectionImpl>(this),
+ oldSctp](const JsepTransceiver& jsepTransceiver) {
std::string transportId = jsepTransceiver.mTransport.mTransportId;
- if (transportId.empty()) {
- return;
+ RefPtr<dom::RTCDtlsTransport> dtlsTransport;
+ if (!transportId.empty()) {
+ nsCString key(transportId.data(), transportId.size());
+ dtlsTransport = mTransportIdToRTCDtlsTransport.GetOrInsertNew(
+ key, GetParentObject());
}
- if (!mTransportIdToRTCDtlsTransport.count(transportId)) {
- mTransportIdToRTCDtlsTransport.emplace(
- transportId, new RTCDtlsTransport(GetParentObject()));
+
+ if (jsepTransceiver.GetMediaType() == SdpMediaSection::kApplication) {
+ // Spec says we only update the RTCSctpTransport when negotiation
+ // completes. This is probably a spec bug.
+ // https://github.com/w3c/webrtc-pc/issues/2898
+ if (!dtlsTransport || !mDataConnection) {
+ return;
+ }
+
+ // Why on earth does the spec use a floating point for this?
+ double maxMessageSize =
+ static_cast<double>(mDataConnection->GetMaxMessageSize());
+ Nullable<uint16_t> maxChannels;
+
+ if (!oldSctp) {
+ mSctpTransport = new RTCSctpTransport(
+ GetParentObject(), *dtlsTransport, maxMessageSize, maxChannels);
+ } else {
+ // Restore the SCTP transport we had before this function was called
+ oldSctp->SetTransport(*dtlsTransport);
+ oldSctp->SetMaxMessageSize(maxMessageSize);
+ oldSctp->SetMaxChannels(maxChannels);
+ mSctpTransport = oldSctp;
+ }
+ } else {
+ RefPtr<dom::RTCRtpTransceiver> domTransceiver =
+ GetTransceiver(jsepTransceiver.GetUuid());
+ if (domTransceiver) {
+ domTransceiver->SetDtlsTransport(dtlsTransport);
+ }
}
});
+}
- for (auto& transceiver : mTransceivers) {
- std::string transportId = transceiver->GetTransportId();
- if (transportId.empty()) {
- continue;
- }
- if (mTransportIdToRTCDtlsTransport.count(transportId)) {
- transceiver->SetDtlsTransport(mTransportIdToRTCDtlsTransport[transportId],
- aMarkAsStable);
- }
+void PeerConnectionImpl::SaveStateForRollback() {
+ // This could change depending on the outcome in
+ // https://github.com/w3c/webrtc-pc/issues/2899
+ if (mSctpTransport) {
+ // We have to save both of these things, because the DTLS transport could
+ // change without the SCTP transport changing.
+ mLastStableSctpTransport = mSctpTransport;
+ mLastStableSctpDtlsTransport = mSctpTransport->Transport();
+ } else {
+ mLastStableSctpTransport = nullptr;
+ mLastStableSctpDtlsTransport = nullptr;
}
- // Spec says we only update the RTCSctpTransport when negotiation completes
+ for (auto& transceiver : mTransceivers) {
+ transceiver->SaveStateForRollback();
+ }
}
-void PeerConnectionImpl::RollbackRTCDtlsTransports() {
+void PeerConnectionImpl::RestoreStateForRollback() {
for (auto& transceiver : mTransceivers) {
transceiver->RollbackToStableDtlsTransport();
}
+
+ mSctpTransport = mLastStableSctpTransport;
+ if (mSctpTransport) {
+ mSctpTransport->SetTransport(*mLastStableSctpDtlsTransport);
+ }
}
-void PeerConnectionImpl::RemoveRTCDtlsTransportsExcept(
- const std::set<std::string>& aTransportIds) {
- for (auto iter = mTransportIdToRTCDtlsTransport.begin();
- iter != mTransportIdToRTCDtlsTransport.end();) {
- if (!aTransportIds.count(iter->first)) {
- iter = mTransportIdToRTCDtlsTransport.erase(iter);
- } else {
- ++iter;
+std::set<RefPtr<dom::RTCDtlsTransport>>
+PeerConnectionImpl::GetActiveTransports() const {
+ std::set<RefPtr<dom::RTCDtlsTransport>> result;
+ for (const auto& transceiver : mTransceivers) {
+ if (transceiver->GetDtlsTransport()) {
+ result.insert(transceiver->GetDtlsTransport());
}
}
+
+ if (mSctpTransport && mSctpTransport->Transport()) {
+ result.insert(mSctpTransport->Transport());
+ }
+ return result;
}
nsresult PeerConnectionImpl::UpdateTransports(const JsepSession& aSession,
const bool forceIceTcp) {
std::set<std::string> finalTransports;
- Maybe<std::string> sctpTransport;
mJsepSession->ForEachTransceiver(
[&, this, self = RefPtr<PeerConnectionImpl>(this)](
const JsepTransceiver& transceiver) {
- if (transceiver.GetMediaType() == SdpMediaSection::kApplication &&
- transceiver.HasTransport()) {
- sctpTransport = Some(transceiver.mTransport.mTransportId);
- }
-
if (transceiver.HasOwnTransport()) {
finalTransports.insert(transceiver.mTransport.mTransportId);
UpdateTransport(transceiver, forceIceTcp);
}
});
- // clean up the unused RTCDtlsTransports
- RemoveRTCDtlsTransportsExcept(finalTransports);
-
mTransportHandler->RemoveTransportsExcept(finalTransports);
for (const auto& transceiverImpl : mTransceivers) {
transceiverImpl->UpdateTransport();
}
- if (sctpTransport.isSome()) {
- auto it = mTransportIdToRTCDtlsTransport.find(*sctpTransport);
- if (it == mTransportIdToRTCDtlsTransport.end()) {
- // What?
- MOZ_ASSERT(false);
- return NS_ERROR_FAILURE;
- }
- if (!mDataConnection) {
- // What?
- MOZ_ASSERT(false);
- return NS_ERROR_FAILURE;
- }
- RefPtr<RTCDtlsTransport> dtlsTransport = it->second;
- // Why on earth does the spec use a floating point for this?
- double maxMessageSize =
- static_cast<double>(mDataConnection->GetMaxMessageSize());
- Nullable<uint16_t> maxChannels;
-
- if (!mSctpTransport) {
- mSctpTransport = new RTCSctpTransport(GetParentObject(), *dtlsTransport,
- maxMessageSize, maxChannels);
- } else {
- mSctpTransport->SetTransport(*dtlsTransport);
- mSctpTransport->SetMaxMessageSize(maxMessageSize);
- mSctpTransport->SetMaxChannels(maxChannels);
- }
- } else {
- mSctpTransport = nullptr;
- }
-
return NS_OK;
}
@@ -4141,6 +4401,9 @@ nsresult PeerConnectionImpl::UpdateMediaPipelines() {
void PeerConnectionImpl::StartIceChecks(const JsepSession& aSession) {
MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(mJsepSession->GetState() == kJsepStateStable);
+
+ auto transports = GetActiveTransports();
if (!mCanRegisterMDNSHostnamesDirectly) {
for (auto& pair : mMDNSHostnamesToRegister) {
@@ -4472,32 +4735,31 @@ std::string PeerConnectionImpl::GetTransportIdMatchingSendTrack(
}
void PeerConnectionImpl::SignalHandler::IceGatheringStateChange_s(
- dom::RTCIceGatheringState aState) {
+ const std::string& aTransportId, dom::RTCIceGathererState aState) {
ASSERT_ON_THREAD(mSTSThread);
-
GetMainThreadSerialEventTarget()->Dispatch(
NS_NewRunnableFunction(__func__,
- [handle = mHandle, aState] {
+ [handle = mHandle, aTransportId, aState] {
PeerConnectionWrapper wrapper(handle);
if (wrapper.impl()) {
wrapper.impl()->IceGatheringStateChange(
- aState);
+ aTransportId, aState);
}
}),
NS_DISPATCH_NORMAL);
}
void PeerConnectionImpl::SignalHandler::IceConnectionStateChange_s(
- dom::RTCIceConnectionState aState) {
+ const std::string& aTransportId, dom::RTCIceTransportState aState) {
ASSERT_ON_THREAD(mSTSThread);
GetMainThreadSerialEventTarget()->Dispatch(
NS_NewRunnableFunction(__func__,
- [handle = mHandle, aState] {
+ [handle = mHandle, aTransportId, aState] {
PeerConnectionWrapper wrapper(handle);
if (wrapper.impl()) {
wrapper.impl()->IceConnectionStateChange(
- aState);
+ aTransportId, aState);
}
}),
NS_DISPATCH_NORMAL);
diff --git a/dom/media/webrtc/jsapi/PeerConnectionImpl.h b/dom/media/webrtc/jsapi/PeerConnectionImpl.h
index 085658b206..d7b54ad721 100644
--- a/dom/media/webrtc/jsapi/PeerConnectionImpl.h
+++ b/dom/media/webrtc/jsapi/PeerConnectionImpl.h
@@ -16,6 +16,7 @@
#include "nsPIDOMWindow.h"
#include "nsIUUIDGenerator.h"
#include "nsIThread.h"
+#include "nsTHashSet.h"
#include "mozilla/Mutex.h"
#include "mozilla/Attributes.h"
@@ -217,8 +218,10 @@ class PeerConnectionImpl final
virtual const std::string& GetName();
// ICE events
- void IceConnectionStateChange(dom::RTCIceConnectionState state);
- void IceGatheringStateChange(dom::RTCIceGatheringState state);
+ void IceConnectionStateChange(const std::string& aTransportId,
+ dom::RTCIceTransportState state);
+ void IceGatheringStateChange(const std::string& aTransportId,
+ dom::RTCIceGathererState state);
void OnCandidateFound(const std::string& aTransportId,
const CandidateInfo& aCandidateInfo);
void UpdateDefaultCandidate(const std::string& defaultAddr,
@@ -411,7 +414,7 @@ class PeerConnectionImpl final
void RecordEndOfCallTelemetry();
- nsresult InitializeDataChannel();
+ nsresult MaybeInitializeDataChannel();
NS_IMETHODIMP_TO_ERRORRESULT_RETREF(nsDOMDataChannel, CreateDataChannel,
ErrorResult& rv, const nsAString& aLabel,
@@ -481,6 +484,9 @@ class PeerConnectionImpl final
aTransceiversOut = mTransceivers.Clone();
}
+ RefPtr<dom::RTCRtpTransceiver> GetTransceiver(
+ const std::string& aTransceiverId);
+
// Gets the RTC Signaling State of the JSEP session
dom::RTCSignalingState GetSignalingState() const;
@@ -499,6 +505,12 @@ class PeerConnectionImpl final
dom::RTCPeerConnectionState GetNewConnectionState() const;
// Returns whether we need to fire a state change event
bool UpdateConnectionState();
+ dom::RTCIceConnectionState GetNewIceConnectionState() const;
+ // Returns whether we need to fire a state change event
+ bool UpdateIceConnectionState();
+ dom::RTCIceGatheringState GetNewIceGatheringState() const;
+ // Returns whether we need to fire a state change event
+ bool UpdateIceGatheringState();
// initialize telemetry for when calls start
void StartCallTelem();
@@ -585,6 +597,9 @@ class PeerConnectionImpl final
void BreakCycles();
+ using RTCDtlsTransportMap =
+ nsTHashMap<nsCStringHashKey, RefPtr<dom::RTCDtlsTransport>>;
+
private:
virtual ~PeerConnectionImpl();
PeerConnectionImpl(const PeerConnectionImpl& rhs);
@@ -805,10 +820,10 @@ class PeerConnectionImpl final
// Ensure ICE transports exist that we might need when offer/answer concludes
void EnsureTransports(const JsepSession& aSession);
- void UpdateRTCDtlsTransports(bool aMarkAsStable);
- void RollbackRTCDtlsTransports();
- void RemoveRTCDtlsTransportsExcept(
- const std::set<std::string>& aTransportIds);
+ void UpdateRTCDtlsTransports();
+ void SaveStateForRollback();
+ void RestoreStateForRollback();
+ std::set<RefPtr<dom::RTCDtlsTransport>> GetActiveTransports() const;
// Activate ICE transports at the conclusion of offer/answer,
// or when rollback occurs.
@@ -861,9 +876,12 @@ class PeerConnectionImpl final
std::set<std::pair<std::string, std::string>> mLocalIceCredentialsToReplace;
nsTArray<RefPtr<dom::RTCRtpTransceiver>> mTransceivers;
- std::map<std::string, RefPtr<dom::RTCDtlsTransport>>
- mTransportIdToRTCDtlsTransport;
+ RTCDtlsTransportMap mTransportIdToRTCDtlsTransport;
RefPtr<dom::RTCSctpTransport> mSctpTransport;
+ // This is similar to [[LastStableStateSender/ReceiverTransport]], but for
+ // DataChannel.
+ RefPtr<dom::RTCSctpTransport> mLastStableSctpTransport;
+ RefPtr<dom::RTCDtlsTransport> mLastStableSctpDtlsTransport;
// Used whenever we need to dispatch a runnable to STS to tweak something
// on our ICE ctx, but are not ready to do so at the moment (eg; we are
@@ -924,8 +942,10 @@ class PeerConnectionImpl final
void ConnectSignals();
// ICE events
- void IceGatheringStateChange_s(dom::RTCIceGatheringState aState);
- void IceConnectionStateChange_s(dom::RTCIceConnectionState aState);
+ void IceGatheringStateChange_s(const std::string& aTransportId,
+ dom::RTCIceGathererState aState);
+ void IceConnectionStateChange_s(const std::string& aTransportId,
+ dom::RTCIceTransportState aState);
void OnCandidateFound_s(const std::string& aTransportId,
const CandidateInfo& aCandidateInfo);
void AlpnNegotiated_s(const std::string& aAlpn, bool aPrivacyRequested);
diff --git a/dom/media/webrtc/jsapi/RTCDtlsTransport.cpp b/dom/media/webrtc/jsapi/RTCDtlsTransport.cpp
index 243f06d2f1..83e0aeee82 100644
--- a/dom/media/webrtc/jsapi/RTCDtlsTransport.cpp
+++ b/dom/media/webrtc/jsapi/RTCDtlsTransport.cpp
@@ -9,7 +9,8 @@
namespace mozilla::dom {
-NS_IMPL_CYCLE_COLLECTION_INHERITED(RTCDtlsTransport, DOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_INHERITED(RTCDtlsTransport, DOMEventTargetHelper,
+ mIceTransport)
NS_IMPL_ADDREF_INHERITED(RTCDtlsTransport, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(RTCDtlsTransport, DOMEventTargetHelper)
@@ -19,7 +20,9 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RTCDtlsTransport)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
RTCDtlsTransport::RTCDtlsTransport(nsPIDOMWindowInner* aWindow)
- : DOMEventTargetHelper(aWindow), mState(RTCDtlsTransportState::New) {}
+ : DOMEventTargetHelper(aWindow),
+ mState(RTCDtlsTransportState::New),
+ mIceTransport(new RTCIceTransport(aWindow)) {}
JSObject* RTCDtlsTransport::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
diff --git a/dom/media/webrtc/jsapi/RTCDtlsTransport.h b/dom/media/webrtc/jsapi/RTCDtlsTransport.h
index 3800502154..3e744b5112 100644
--- a/dom/media/webrtc/jsapi/RTCDtlsTransport.h
+++ b/dom/media/webrtc/jsapi/RTCDtlsTransport.h
@@ -6,6 +6,7 @@
#define _RTCDtlsTransport_h_
#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/dom/RTCIceTransport.h"
#include "mozilla/RefPtr.h"
#include "js/RootingAPI.h"
#include "transport/transportlayer.h"
@@ -30,6 +31,7 @@ class RTCDtlsTransport : public DOMEventTargetHelper {
JS::Handle<JSObject*> aGivenProto) override;
IMPL_EVENT_HANDLER(statechange)
RTCDtlsTransportState State() const { return mState; }
+ RefPtr<RTCIceTransport> IceTransport() { return mIceTransport; }
void UpdateStateNoEvent(TransportLayer::State aState);
void UpdateState(TransportLayer::State aState);
@@ -38,6 +40,7 @@ class RTCDtlsTransport : public DOMEventTargetHelper {
virtual ~RTCDtlsTransport() = default;
RTCDtlsTransportState mState;
+ RefPtr<RTCIceTransport> mIceTransport;
};
} // namespace mozilla::dom
diff --git a/dom/media/webrtc/jsapi/RTCIceTransport.cpp b/dom/media/webrtc/jsapi/RTCIceTransport.cpp
new file mode 100644
index 0000000000..4c5e6eef4f
--- /dev/null
+++ b/dom/media/webrtc/jsapi/RTCIceTransport.cpp
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "RTCIceTransport.h"
+#include "mozilla/dom/Event.h"
+#include "mozilla/dom/EventBinding.h"
+#include "mozilla/dom/RTCIceTransportBinding.h"
+
+namespace mozilla::dom {
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(RTCIceTransport, DOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(RTCIceTransport, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(RTCIceTransport, DOMEventTargetHelper)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RTCIceTransport)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+RTCIceTransport::RTCIceTransport(nsPIDOMWindowInner* aWindow)
+ : DOMEventTargetHelper(aWindow),
+ mState(RTCIceTransportState::New),
+ mGatheringState(RTCIceGathererState::New) {}
+
+JSObject* RTCIceTransport::WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) {
+ return RTCIceTransport_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+void RTCIceTransport::SetState(RTCIceTransportState aState) { mState = aState; }
+
+void RTCIceTransport::SetGatheringState(RTCIceGathererState aState) {
+ mGatheringState = aState;
+}
+
+void RTCIceTransport::FireStateChangeEvent() {
+ EventInit init;
+ init.mBubbles = false;
+ init.mCancelable = false;
+
+ RefPtr<Event> event = Event::Constructor(this, u"statechange"_ns, init);
+
+ DispatchTrustedEvent(event);
+}
+
+void RTCIceTransport::FireGatheringStateChangeEvent() {
+ EventInit init;
+ init.mBubbles = false;
+ init.mCancelable = false;
+
+ RefPtr<Event> event =
+ Event::Constructor(this, u"gatheringstatechange"_ns, init);
+
+ DispatchTrustedEvent(event);
+}
+
+} // namespace mozilla::dom
diff --git a/dom/media/webrtc/jsapi/RTCIceTransport.h b/dom/media/webrtc/jsapi/RTCIceTransport.h
new file mode 100644
index 0000000000..931aa66bac
--- /dev/null
+++ b/dom/media/webrtc/jsapi/RTCIceTransport.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_DOM_MEDIA_WEBRTC_JSAPI_RTCICETRANSPORT_H_
+#define MOZILLA_DOM_MEDIA_WEBRTC_JSAPI_RTCICETRANSPORT_H_
+
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/RefPtr.h"
+#include "js/RootingAPI.h"
+#include "transport/transportlayer.h"
+
+class nsPIDOMWindowInner;
+
+namespace mozilla::dom {
+
+enum class RTCIceTransportState : uint8_t;
+enum class RTCIceGathererState : uint8_t;
+
+class RTCIceTransport : public DOMEventTargetHelper {
+ public:
+ explicit RTCIceTransport(nsPIDOMWindowInner* aWindow);
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(RTCIceTransport,
+ DOMEventTargetHelper)
+
+ // webidl
+ JSObject* WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) override;
+ IMPL_EVENT_HANDLER(statechange)
+ IMPL_EVENT_HANDLER(gatheringstatechange)
+ RTCIceTransportState State() const { return mState; }
+ RTCIceGathererState GatheringState() const { return mGatheringState; }
+
+ void SetState(RTCIceTransportState aState);
+ void SetGatheringState(RTCIceGathererState aState);
+
+ void FireStateChangeEvent();
+ void FireGatheringStateChangeEvent();
+
+ private:
+ virtual ~RTCIceTransport() = default;
+
+ RTCIceTransportState mState;
+ RTCIceGathererState mGatheringState;
+};
+
+} // namespace mozilla::dom
+#endif // MOZILLA_DOM_MEDIA_WEBRTC_JSAPI_RTCICETRANSPORT_H_
diff --git a/dom/media/webrtc/jsapi/RTCRtpReceiver.cpp b/dom/media/webrtc/jsapi/RTCRtpReceiver.cpp
index efe83fb782..96db9fc312 100644
--- a/dom/media/webrtc/jsapi/RTCRtpReceiver.cpp
+++ b/dom/media/webrtc/jsapi/RTCRtpReceiver.cpp
@@ -709,9 +709,9 @@ void RTCRtpReceiver::UpdateTransport() {
// Add unique payload types as a last-ditch fallback
auto uniquePts = GetJsepTransceiver()
.mRecvTrack.GetNegotiatedDetails()
- ->GetUniquePayloadTypes();
+ ->GetUniqueReceivePayloadTypes();
for (unsigned char& uniquePt : uniquePts) {
- filter->AddUniquePT(uniquePt);
+ filter->AddUniqueReceivePT(uniquePt);
}
}
diff --git a/dom/media/webrtc/jsapi/RTCRtpSender.cpp b/dom/media/webrtc/jsapi/RTCRtpSender.cpp
index 4ba0491521..da198c62e4 100644
--- a/dom/media/webrtc/jsapi/RTCRtpSender.cpp
+++ b/dom/media/webrtc/jsapi/RTCRtpSender.cpp
@@ -1502,7 +1502,6 @@ Maybe<RTCRtpSender::VideoConfig> RTCRtpSender::GetNewVideoConfig() {
case dom::MediaSourceEnum::Microphone:
case dom::MediaSourceEnum::AudioCapture:
- case dom::MediaSourceEnum::EndGuard_:
MOZ_ASSERT(false);
break;
}
diff --git a/dom/media/webrtc/jsapi/RTCRtpTransceiver.cpp b/dom/media/webrtc/jsapi/RTCRtpTransceiver.cpp
index b219619f87..6b7b456e46 100644
--- a/dom/media/webrtc/jsapi/RTCRtpTransceiver.cpp
+++ b/dom/media/webrtc/jsapi/RTCRtpTransceiver.cpp
@@ -239,7 +239,6 @@ SdpDirectionAttribute::Direction ToSdpDirection(
case dom::RTCRtpTransceiverDirection::Inactive:
case dom::RTCRtpTransceiverDirection::Stopped:
return SdpDirectionAttribute::Direction::kInactive;
- case dom::RTCRtpTransceiverDirection::EndGuard_:;
}
MOZ_CRASH("Invalid transceiver direction!");
}
@@ -279,12 +278,13 @@ void RTCRtpTransceiver::Init(const RTCRtpTransceiverInit& aInit,
mDirection = aInit.mDirection;
}
-void RTCRtpTransceiver::SetDtlsTransport(dom::RTCDtlsTransport* aDtlsTransport,
- bool aStable) {
+void RTCRtpTransceiver::SetDtlsTransport(
+ dom::RTCDtlsTransport* aDtlsTransport) {
mDtlsTransport = aDtlsTransport;
- if (aStable) {
- mLastStableDtlsTransport = mDtlsTransport;
- }
+}
+
+void RTCRtpTransceiver::SaveStateForRollback() {
+ mLastStableDtlsTransport = mDtlsTransport;
}
void RTCRtpTransceiver::RollbackToStableDtlsTransport() {
@@ -366,12 +366,17 @@ void RTCRtpTransceiver::InitConduitControl() {
}
void RTCRtpTransceiver::Close() {
- // Called via PCImpl::Close -> PCImpl::CloseInt -> PCImpl::ShutdownMedia ->
- // PCMedia::SelfDestruct. Satisfies step 7 of
+ // Called via PCImpl::Close
+ // Satisfies steps 7 and 9 of
// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-close
+ // No events are fired for this.
mShutdown = true;
if (mDtlsTransport) {
mDtlsTransport->UpdateStateNoEvent(TransportLayer::TS_CLOSED);
+ // Might not be set if we're cycle-collecting
+ if (mDtlsTransport->IceTransport()) {
+ mDtlsTransport->IceTransport()->SetState(RTCIceTransportState::Closed);
+ }
}
StopImpl();
}
@@ -401,9 +406,9 @@ void RTCRtpTransceiver::Unlink() {
// TODO: Only called from one place in PeerConnectionImpl, synchronously, when
// the JSEP engine has successfully completed an offer/answer exchange. This is
// a bit squirrely, since identity validation happens asynchronously in
-// PeerConnection.jsm. This probably needs to happen once all the "in parallel"
-// steps have succeeded, but before we queue the task for JS observable state
-// updates.
+// PeerConnection.sys.mjs. This probably needs to happen once all the "in
+// parallel" steps have succeeded, but before we queue the task for JS
+// observable state updates.
nsresult RTCRtpTransceiver::UpdateTransport() {
if (!mHasTransport) {
return NS_OK;
@@ -439,9 +444,9 @@ void RTCRtpTransceiver::ResetSync() { mSyncGroup = std::string(); }
// TODO: Only called from one place in PeerConnectionImpl, synchronously, when
// the JSEP engine has successfully completed an offer/answer exchange. This is
// a bit squirrely, since identity validation happens asynchronously in
-// PeerConnection.jsm. This probably needs to happen once all the "in parallel"
-// steps have succeeded, but before we queue the task for JS observable state
-// updates.
+// PeerConnection.sys.mjs. This probably needs to happen once all the "in
+// parallel" steps have succeeded, but before we queue the task for JS
+// observable state updates.
nsresult RTCRtpTransceiver::SyncWithMatchingVideoConduits(
nsTArray<RefPtr<RTCRtpTransceiver>>& transceivers) {
if (mStopped) {
diff --git a/dom/media/webrtc/jsapi/RTCRtpTransceiver.h b/dom/media/webrtc/jsapi/RTCRtpTransceiver.h
index afa6142d35..4fa7ef157c 100644
--- a/dom/media/webrtc/jsapi/RTCRtpTransceiver.h
+++ b/dom/media/webrtc/jsapi/RTCRtpTransceiver.h
@@ -119,7 +119,8 @@ class RTCRtpTransceiver : public nsISupports, public nsWrapperCache {
void SyncFromJsep(const JsepSession& aSession);
std::string GetMidAscii() const;
- void SetDtlsTransport(RTCDtlsTransport* aDtlsTransport, bool aStable);
+ void SetDtlsTransport(RTCDtlsTransport* aDtlsTransport);
+ void SaveStateForRollback();
void RollbackToStableDtlsTransport();
std::string GetTransportId() const {
diff --git a/dom/media/webrtc/jsapi/moz.build b/dom/media/webrtc/jsapi/moz.build
index 78a6241cd6..05920fc151 100644
--- a/dom/media/webrtc/jsapi/moz.build
+++ b/dom/media/webrtc/jsapi/moz.build
@@ -31,6 +31,7 @@ UNIFIED_SOURCES += [
"RTCEncodedAudioFrame.cpp",
"RTCEncodedFrameBase.cpp",
"RTCEncodedVideoFrame.cpp",
+ "RTCIceTransport.cpp",
"RTCRtpReceiver.cpp",
"RTCRtpScriptTransform.cpp",
"RTCRtpScriptTransformer.cpp",
@@ -50,6 +51,7 @@ EXPORTS.mozilla.dom += [
"RTCEncodedAudioFrame.h",
"RTCEncodedFrameBase.h",
"RTCEncodedVideoFrame.h",
+ "RTCIceTransport.h",
"RTCRtpReceiver.h",
"RTCRtpScriptTransform.h",
"RTCRtpScriptTransformer.h",