Bug 1265827: Implement RTCPeerConnectionState. r=jib,webidl,smaug

Differential Revision: https://phabricator.services.mozilla.com/D168143
This commit is contained in:
Byron Campen 2023-03-14 13:27:10 +00:00
Родитель c61882a351
Коммит b01ce6d90d
9 изменённых файлов: 231 добавлений и 46 удалений

Просмотреть файл

@ -535,6 +535,7 @@ class RTCPeerConnection {
this.makeGetterSetterEH("ondatachannel"); this.makeGetterSetterEH("ondatachannel");
this.makeGetterSetterEH("oniceconnectionstatechange"); this.makeGetterSetterEH("oniceconnectionstatechange");
this.makeGetterSetterEH("onicegatheringstatechange"); this.makeGetterSetterEH("onicegatheringstatechange");
this.makeGetterSetterEH("onconnectionstatechange");
this.makeGetterSetterEH("onidentityresult"); this.makeGetterSetterEH("onidentityresult");
this.makeGetterSetterEH("onpeeridentity"); this.makeGetterSetterEH("onpeeridentity");
this.makeGetterSetterEH("onidpassertionerror"); this.makeGetterSetterEH("onidpassertionerror");
@ -1596,6 +1597,9 @@ class RTCPeerConnection {
get iceConnectionState() { get iceConnectionState() {
return this._iceConnectionState; return this._iceConnectionState;
} }
get connectionState() {
return this._pc.connectionState;
}
get signalingState() { get signalingState() {
// checking for our local pc closed indication // checking for our local pc closed indication
@ -1913,6 +1917,11 @@ class PeerConnectionObserver {
this._dompc.handleIceGatheringStateChange(); this._dompc.handleIceGatheringStateChange();
break; break;
case "ConnectionState":
_globalPCList.notifyLifecycleObservers(this, "connectionstatechange");
this.dispatchEvent(new this._win.Event("connectionstatechange"));
break;
default: default:
this._dompc.logWarning("Unhandled state type: " + state); this._dompc.logWarning("Unhandled state type: " + state);
break; break;

Просмотреть файл

@ -80,6 +80,7 @@
#include "js/RootingAPI.h" // JS::{{,Mutable}Handle,Rooted} #include "js/RootingAPI.h" // JS::{{,Mutable}Handle,Rooted}
#include "mozilla/PeerIdentity.h" #include "mozilla/PeerIdentity.h"
#include "mozilla/dom/RTCCertificate.h" #include "mozilla/dom/RTCCertificate.h"
#include "mozilla/dom/RTCDtlsTransportBinding.h" // RTCDtlsTransportState
#include "mozilla/dom/RTCRtpReceiverBinding.h" #include "mozilla/dom/RTCRtpReceiverBinding.h"
#include "mozilla/dom/RTCRtpSenderBinding.h" #include "mozilla/dom/RTCRtpSenderBinding.h"
#include "mozilla/dom/RTCStatsReportBinding.h" #include "mozilla/dom/RTCStatsReportBinding.h"
@ -329,6 +330,7 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
mSignalingState(RTCSignalingState::Stable), mSignalingState(RTCSignalingState::Stable),
mIceConnectionState(RTCIceConnectionState::New), mIceConnectionState(RTCIceConnectionState::New),
mIceGatheringState(RTCIceGatheringState::New), mIceGatheringState(RTCIceGatheringState::New),
mConnectionState(RTCPeerConnectionState::New),
mWindow(do_QueryInterface(aGlobal ? aGlobal->GetAsSupports() : nullptr)), mWindow(do_QueryInterface(aGlobal ? aGlobal->GetAsSupports() : nullptr)),
mCertificate(nullptr), mCertificate(nullptr),
mSTSThread(nullptr), mSTSThread(nullptr),
@ -1973,6 +1975,136 @@ nsresult PeerConnectionImpl::OnAlpnNegotiated(bool aPrivacyRequested) {
return NS_OK; return NS_OK;
} }
void PeerConnectionImpl::OnDtlsStateChange(const std::string& aTransportId,
TransportLayer::State aState) {
auto it = mTransportIdToRTCDtlsTransport.find(aTransportId);
if (it != mTransportIdToRTCDtlsTransport.end()) {
it->second->UpdateState(aState);
}
UpdateConnectionState();
}
RTCPeerConnectionState PeerConnectionImpl::GetNewConnectionState() const {
// closed The RTCPeerConnection object's [[IsClosed]] slot is true.
if (IsClosed()) {
return RTCPeerConnectionState::Closed;
}
// 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());
}
// failed The previous state doesn't apply and any RTCIceTransports are
// in the "failed" state or any RTCDtlsTransports are in the "failed" state.
// NOTE: "any RTCIceTransports are in the failed state" is equivalent to
// mIceConnectionState == Failed
if (mIceConnectionState == RTCIceConnectionState::Failed ||
statesFound.count(RTCDtlsTransportState::Failed)) {
return RTCPeerConnectionState::Failed;
}
// disconnected None of the previous states apply and any
// RTCIceTransports are in the "disconnected" state.
// NOTE: "any RTCIceTransports are in the disconnected state" is equivalent to
// mIceConnectionState == Disconnected.
if (mIceConnectionState == RTCIceConnectionState::Disconnected) {
return RTCPeerConnectionState::Disconnected;
}
// new None of the previous states apply and all RTCIceTransports are
// in the "new" or "closed" state, and all RTCDtlsTransports are in the "new"
// or "closed" state, or there are no transports.
// NOTE: "all RTCIceTransports are in the new or closed state" is equivalent
// to mIceConnectionState == New.
if (mIceConnectionState == RTCIceConnectionState::New &&
!statesFound.count(RTCDtlsTransportState::Connecting) &&
!statesFound.count(RTCDtlsTransportState::Connected) &&
!statesFound.count(RTCDtlsTransportState::Failed)) {
return RTCPeerConnectionState::New;
}
// No transports
if (statesFound.empty()) {
return RTCPeerConnectionState::New;
}
// connecting None of the previous states apply and any
// RTCIceTransport is in the "new" or "checking" state or any
// RTCDtlsTransport is in the "new" or "connecting" state.
// NOTE: "None of the previous states apply and any RTCIceTransport is in the
// "new" or "checking" state" is equivalent to mIceConnectionState ==
// Checking.
if (mIceConnectionState == RTCIceConnectionState::Checking ||
statesFound.count(RTCDtlsTransportState::New) ||
statesFound.count(RTCDtlsTransportState::Connecting)) {
return RTCPeerConnectionState::Connecting;
}
// connected None of the previous states apply and all RTCIceTransports are
// in the "connected", "completed" or "closed" state, and all
// RTCDtlsTransports are in the "connected" or "closed" state.
// NOTE: "None of the previous states apply and all RTCIceTransports are in
// the "connected", "completed" or "closed" state" is equivalent to
// mIceConnectionState == Connected.
if (mIceConnectionState == RTCIceConnectionState::Connected &&
!statesFound.count(RTCDtlsTransportState::New) &&
!statesFound.count(RTCDtlsTransportState::Failed) &&
!statesFound.count(RTCDtlsTransportState::Connecting)) {
return RTCPeerConnectionState::Connected;
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// THERE IS NO CATCH-ALL NONE-OF-THE-ABOVE IN THE SPEC! THIS IS REALLY BAD! !!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Let's try to figure out how bad, precisely.
// Any one of these will cause us to bail above.
MOZ_ASSERT(mIceConnectionState != RTCIceConnectionState::Failed &&
mIceConnectionState != RTCIceConnectionState::Disconnected &&
mIceConnectionState != RTCIceConnectionState::Checking);
MOZ_ASSERT(!statesFound.count(RTCDtlsTransportState::New) &&
!statesFound.count(RTCDtlsTransportState::Connecting) &&
!statesFound.count(RTCDtlsTransportState::Failed));
// One of these must be set, or the empty() check would have failed above.
MOZ_ASSERT(statesFound.count(RTCDtlsTransportState::Connected) ||
statesFound.count(RTCDtlsTransportState::Closed));
// Here are our remaining possibilities:
// ICE connected, !statesFound.count(Connected), statesFound.count(Closed)
// ICE connected, statesFound.count(Connected), !statesFound.count(Closed)
// ICE connected, statesFound.count(Connected), statesFound.count(Closed)
// All three of these would result in returning Connected above.
// ICE new, !statesFound.count(Connected), statesFound.count(Closed)
// This results in returning New above. Whew.
// ICE new, statesFound.count(Connected), !statesFound.count(Closed)
// ICE new, statesFound.count(Connected), statesFound.count(Closed)
// These would make it all the way here! Very weird state though, for all
// ICE transports to be new/closed, but having a connected DTLS transport.
// Handle this as a non-transition, just in case.
return mConnectionState;
}
void PeerConnectionImpl::UpdateConnectionState() {
auto newState = GetNewConnectionState();
if (newState != mConnectionState) {
CSFLogDebug(LOGTAG, "%s: %d -> %d (%p)", __FUNCTION__,
static_cast<int>(mConnectionState), static_cast<int>(newState),
this);
mConnectionState = newState;
if (mConnectionState != RTCPeerConnectionState::Closed) {
JSErrorResult jrv;
mPCObserver->OnStateChange(PCObserverStateType::ConnectionState, jrv);
}
}
}
void PeerConnectionImpl::OnMediaError(const std::string& aError) { void PeerConnectionImpl::OnMediaError(const std::string& aError) {
CSFLogError(LOGTAG, "Encountered media error! %s", aError.c_str()); CSFLogError(LOGTAG, "Encountered media error! %s", aError.c_str());
// TODO: Let content know about this somehow. // TODO: Let content know about this somehow.
@ -2191,6 +2323,15 @@ PeerConnectionImpl::IceGatheringState(RTCIceGatheringState* aState) {
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
PeerConnectionImpl::ConnectionState(RTCPeerConnectionState* aState) {
PC_AUTO_ENTER_API_CALL_NO_CHECK();
MOZ_ASSERT(aState);
*aState = mConnectionState;
return NS_OK;
}
nsresult PeerConnectionImpl::CheckApiState(bool assert_ice_ready) const { nsresult PeerConnectionImpl::CheckApiState(bool assert_ice_ready) const {
PC_AUTO_ENTER_API_CALL_NO_CHECK(); PC_AUTO_ENTER_API_CALL_NO_CHECK();
MOZ_ASSERT(mTrickle || !assert_ice_ready || MOZ_ASSERT(mTrickle || !assert_ice_ready ||
@ -2289,6 +2430,7 @@ PeerConnectionImpl::Close() {
} }
mSignalingState = RTCSignalingState::Closed; mSignalingState = RTCSignalingState::Closed;
mConnectionState = RTCPeerConnectionState::Closed;
if (!mTransportHandler) { if (!mTransportHandler) {
// We were never initialized, apparently. // We were never initialized, apparently.
@ -2752,6 +2894,10 @@ void PeerConnectionImpl::DoSetDescriptionSuccessPostProcessing(
UpdateNegotiationNeeded(); UpdateNegotiationNeeded();
} }
// Spec does not actually tell us to do this, but that is probably a
// spec bug.
UpdateConnectionState();
JSErrorResult jrv; JSErrorResult jrv;
if (newSignalingState != mSignalingState) { if (newSignalingState != mSignalingState) {
mSignalingState = newSignalingState; mSignalingState = newSignalingState;
@ -2963,7 +3109,9 @@ void PeerConnectionImpl::IceConnectionStateChange(
dom::RTCIceConnectionState domState) { dom::RTCIceConnectionState domState) {
PC_AUTO_ENTER_API_CALL_VOID_RETURN(false); PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
CSFLogDebug(LOGTAG, "%s: %d", __FUNCTION__, static_cast<int>(domState)); CSFLogDebug(LOGTAG, "%s: %d -> %d", __FUNCTION__,
static_cast<int>(mIceConnectionState),
static_cast<int>(domState));
if (domState == mIceConnectionState) { if (domState == mIceConnectionState) {
// no work to be done since the states are the same. // no work to be done since the states are the same.
@ -3006,6 +3154,7 @@ void PeerConnectionImpl::IceConnectionStateChange(
WrappableJSErrorResult rv; WrappableJSErrorResult rv;
mPCObserver->OnStateChange(PCObserverStateType::IceConnectionState, rv); mPCObserver->OnStateChange(PCObserverStateType::IceConnectionState, rv);
UpdateConnectionState();
} }
void PeerConnectionImpl::OnCandidateFound(const std::string& aTransportId, void PeerConnectionImpl::OnCandidateFound(const std::string& aTransportId,
@ -3588,19 +3737,29 @@ void PeerConnectionImpl::EnsureTransports(const JsepSession& aSession) {
} }
void PeerConnectionImpl::UpdateRTCDtlsTransports(bool aMarkAsStable) { void PeerConnectionImpl::UpdateRTCDtlsTransports(bool aMarkAsStable) {
for (auto& transceiver : mTransceivers) { for (const auto& jsepTransceiver : mJsepSession->GetTransceivers()) {
std::string transportId = transceiver->GetTransportId(); std::string transportId = jsepTransceiver->mTransport.mTransportId;
if (transportId.empty()) { if (transportId.empty()) {
continue; continue;
} }
if (!mTransportIdToRTCDtlsTransport.count(transportId)) { if (!mTransportIdToRTCDtlsTransport.count(transportId)) {
mTransportIdToRTCDtlsTransport.emplace( mTransportIdToRTCDtlsTransport.emplace(
transportId, new RTCDtlsTransport(transceiver->GetParentObject())); transportId, new RTCDtlsTransport(GetParentObject()));
} }
transceiver->SetDtlsTransport(mTransportIdToRTCDtlsTransport[transportId],
aMarkAsStable);
} }
for (auto& transceiver : mTransceivers) {
std::string transportId = transceiver->GetTransportId();
if (transportId.empty()) {
continue;
}
if (mTransportIdToRTCDtlsTransport.count(transportId)) {
transceiver->SetDtlsTransport(mTransportIdToRTCDtlsTransport[transportId],
aMarkAsStable);
}
}
// TODO (bug 1278299): DataChannel transport
} }
void PeerConnectionImpl::RollbackRTCDtlsTransports() { void PeerConnectionImpl::RollbackRTCDtlsTransports() {
@ -3640,6 +3799,8 @@ nsresult PeerConnectionImpl::UpdateTransports(const JsepSession& aSession,
transceiverImpl->UpdateTransport(); transceiverImpl->UpdateTransport();
} }
// TODO(bug 1278299): DataChannel transport object
return NS_OK; return NS_OK;
} }
@ -3807,6 +3968,10 @@ void PeerConnectionImpl::SignalHandler::ConnectSignals() {
this, &PeerConnectionImpl::SignalHandler::OnCandidateFound_s); this, &PeerConnectionImpl::SignalHandler::OnCandidateFound_s);
mSource->SignalAlpnNegotiated.connect( mSource->SignalAlpnNegotiated.connect(
this, &PeerConnectionImpl::SignalHandler::AlpnNegotiated_s); this, &PeerConnectionImpl::SignalHandler::AlpnNegotiated_s);
mSource->SignalStateChange.connect(
this, &PeerConnectionImpl::SignalHandler::ConnectionStateChange_s);
mSource->SignalRtcpStateChange.connect(
this, &PeerConnectionImpl::SignalHandler::ConnectionStateChange_s);
} }
void PeerConnectionImpl::AddIceCandidate(const std::string& aCandidate, void PeerConnectionImpl::AddIceCandidate(const std::string& aCandidate,
@ -4104,6 +4269,20 @@ void PeerConnectionImpl::SignalHandler::AlpnNegotiated_s(
NS_DISPATCH_NORMAL); NS_DISPATCH_NORMAL);
} }
void PeerConnectionImpl::SignalHandler::ConnectionStateChange_s(
const std::string& aTransportId, TransportLayer::State aState) {
GetMainThreadSerialEventTarget()->Dispatch(
NS_NewRunnableFunction(__func__,
[handle = mHandle, aTransportId, aState] {
PeerConnectionWrapper wrapper(handle);
if (wrapper.impl()) {
wrapper.impl()->OnDtlsStateChange(aTransportId,
aState);
}
}),
NS_DISPATCH_NORMAL);
}
/** /**
* Tells you if any local track is isolated to a specific peer identity. * Tells you if any local track is isolated to a specific peer identity.
* Obviously, we want all the tracks to be isolated equally so that they can * Obviously, we want all the tracks to be isolated equally so that they can

Просмотреть файл

@ -368,6 +368,14 @@ class PeerConnectionImpl final
return mIceGatheringState; return mIceGatheringState;
} }
NS_IMETHODIMP ConnectionState(mozilla::dom::RTCPeerConnectionState* aState);
mozilla::dom::RTCPeerConnectionState ConnectionState() {
mozilla::dom::RTCPeerConnectionState state;
ConnectionState(&state);
return state;
}
NS_IMETHODIMP Close(); NS_IMETHODIMP Close();
void Close(ErrorResult& rv) { rv = Close(); } void Close(ErrorResult& rv) { rv = Close(); }
@ -469,6 +477,11 @@ class PeerConnectionImpl final
// called when DTLS connects; we only need this once // called when DTLS connects; we only need this once
nsresult OnAlpnNegotiated(bool aPrivacyRequested); nsresult OnAlpnNegotiated(bool aPrivacyRequested);
void OnDtlsStateChange(const std::string& aTransportId,
TransportLayer::State aState);
void UpdateConnectionState();
dom::RTCPeerConnectionState GetNewConnectionState() const;
// initialize telemetry for when calls start // initialize telemetry for when calls start
void StartCallTelem(); void StartCallTelem();
@ -599,6 +612,8 @@ class PeerConnectionImpl final
mozilla::dom::RTCIceConnectionState mIceConnectionState; mozilla::dom::RTCIceConnectionState mIceConnectionState;
mozilla::dom::RTCIceGatheringState mIceGatheringState; mozilla::dom::RTCIceGatheringState mIceGatheringState;
mozilla::dom::RTCPeerConnectionState mConnectionState;
RefPtr<PeerConnectionObserver> mPCObserver; RefPtr<PeerConnectionObserver> mPCObserver;
nsCOMPtr<nsPIDOMWindowInner> mWindow; nsCOMPtr<nsPIDOMWindowInner> mWindow;
@ -869,6 +884,8 @@ class PeerConnectionImpl final
void OnCandidateFound_s(const std::string& aTransportId, void OnCandidateFound_s(const std::string& aTransportId,
const CandidateInfo& aCandidateInfo); const CandidateInfo& aCandidateInfo);
void AlpnNegotiated_s(const std::string& aAlpn, bool aPrivacyRequested); void AlpnNegotiated_s(const std::string& aAlpn, bool aPrivacyRequested);
void ConnectionStateChange_s(const std::string& aTransportId,
TransportLayer::State aState);
private: private:
const std::string mHandle; const std::string mHandle;

Просмотреть файл

@ -226,17 +226,6 @@ void RTCRtpTransceiver::Init(const RTCRtpTransceiverInit& aInit,
InitConduitControl(); InitConduitControl();
} }
auto self = nsMainThreadPtrHandle<RTCRtpTransceiver>(
new nsMainThreadPtrHolder<RTCRtpTransceiver>(
"RTCRtpTransceiver::RTCRtpTransceiver::self", this, false));
mStsThread->Dispatch(
NS_NewRunnableFunction("RTCRtpTransceiver::RTCRtpTransceiver", [self] {
self->mTransportHandler->SignalStateChange.connect(
self.get(), &RTCRtpTransceiver::UpdateDtlsTransportState);
self->mTransportHandler->SignalRtcpStateChange.connect(
self.get(), &RTCRtpTransceiver::UpdateDtlsTransportState);
}));
mSender->SetStreams(aInit.mStreams); mSender->SetStreams(aInit.mStreams);
mDirection = aInit.mDirection; mDirection = aInit.mDirection;
} }
@ -253,23 +242,6 @@ void RTCRtpTransceiver::RollbackToStableDtlsTransport() {
mDtlsTransport = mLastStableDtlsTransport; mDtlsTransport = mLastStableDtlsTransport;
} }
void RTCRtpTransceiver::UpdateDtlsTransportState(
const std::string& aTransportId, TransportLayer::State aState) {
if (!GetMainThreadSerialEventTarget()->IsOnCurrentThread()) {
GetMainThreadSerialEventTarget()->Dispatch(
WrapRunnable(this, &RTCRtpTransceiver::UpdateDtlsTransportState,
aTransportId, aState),
NS_DISPATCH_NORMAL);
return;
}
if (!mDtlsTransport) {
return;
}
mDtlsTransport->UpdateState(aState);
}
void RTCRtpTransceiver::InitAudio() { void RTCRtpTransceiver::InitAudio() {
mConduit = AudioSessionConduit::Create(mCallWrapper, mStsThread); mConduit = AudioSessionConduit::Create(mCallWrapper, mStsThread);
@ -888,10 +860,8 @@ void RTCRtpTransceiver::StopImpl() {
auto self = nsMainThreadPtrHandle<RTCRtpTransceiver>( auto self = nsMainThreadPtrHandle<RTCRtpTransceiver>(
new nsMainThreadPtrHolder<RTCRtpTransceiver>( new nsMainThreadPtrHolder<RTCRtpTransceiver>(
"RTCRtpTransceiver::StopImpl::self", this, false)); "RTCRtpTransceiver::StopImpl::self", this, false));
mStsThread->Dispatch(NS_NewRunnableFunction(__func__, [self] { mStsThread->Dispatch(NS_NewRunnableFunction(
self->disconnect_all(); __func__, [self] { self->mTransportHandler = nullptr; }));
self->mTransportHandler = nullptr;
}));
} }
bool RTCRtpTransceiver::IsVideo() const { return mIsVideo; } bool RTCRtpTransceiver::IsVideo() const { return mIsVideo; }

Просмотреть файл

@ -51,9 +51,7 @@ class RTCRtpSender;
* Audio/VideoConduit for feeding RTP/RTCP into webrtc.org for decoding, and * Audio/VideoConduit for feeding RTP/RTCP into webrtc.org for decoding, and
* feeding audio/video frames into webrtc.org for encoding into RTP/RTCP. * feeding audio/video frames into webrtc.org for encoding into RTP/RTCP.
*/ */
class RTCRtpTransceiver : public nsISupports, class RTCRtpTransceiver : public nsISupports, public nsWrapperCache {
public nsWrapperCache,
public sigslot::has_slots<> {
public: public:
/** /**
* |aSendTrack| might or might not be set. * |aSendTrack| might or might not be set.
@ -112,8 +110,6 @@ class RTCRtpTransceiver : public nsISupports,
void SetJsepSession(JsepSession* aJsepSession); void SetJsepSession(JsepSession* aJsepSession);
std::string GetMidAscii() const; std::string GetMidAscii() const;
void UpdateDtlsTransportState(const std::string& aTransportId,
TransportLayer::State aState);
void SetDtlsTransport(RTCDtlsTransport* aDtlsTransport, bool aStable); void SetDtlsTransport(RTCDtlsTransport* aDtlsTransport, bool aStable);
void RollbackToStableDtlsTransport(); void RollbackToStableDtlsTransport();

Просмотреть файл

@ -108,6 +108,7 @@ interface PeerConnectionImpl {
readonly attribute RTCIceConnectionState iceConnectionState; readonly attribute RTCIceConnectionState iceConnectionState;
readonly attribute RTCIceGatheringState iceGatheringState; readonly attribute RTCIceGatheringState iceGatheringState;
readonly attribute RTCPeerConnectionState connectionState;
readonly attribute RTCSignalingState signalingState; readonly attribute RTCSignalingState signalingState;
attribute DOMString id; attribute DOMString id;

Просмотреть файл

@ -10,7 +10,8 @@ enum PCObserverStateType {
"None", "None",
"IceConnectionState", "IceConnectionState",
"IceGatheringState", "IceGatheringState",
"SignalingState" "SignalingState",
"ConnectionState",
}; };
enum PCError { enum PCError {

Просмотреть файл

@ -36,6 +36,15 @@ enum RTCIceConnectionState {
"closed" "closed"
}; };
enum RTCPeerConnectionState {
"closed",
"failed",
"disconnected",
"new",
"connecting",
"connected"
};
enum mozPacketDumpType { enum mozPacketDumpType {
"rtp", // dump unencrypted rtp as the MediaPipeline sees it "rtp", // dump unencrypted rtp as the MediaPipeline sees it
"srtp", // dump encrypted rtp as the MediaPipeline sees it "srtp", // dump encrypted rtp as the MediaPipeline sees it
@ -107,6 +116,7 @@ interface RTCPeerConnection : EventTarget {
readonly attribute boolean? canTrickleIceCandidates; readonly attribute boolean? canTrickleIceCandidates;
readonly attribute RTCIceGatheringState iceGatheringState; readonly attribute RTCIceGatheringState iceGatheringState;
readonly attribute RTCIceConnectionState iceConnectionState; readonly attribute RTCIceConnectionState iceConnectionState;
readonly attribute RTCPeerConnectionState connectionState;
undefined restartIce (); undefined restartIce ();
[Pref="media.peerconnection.identity.enabled"] [Pref="media.peerconnection.identity.enabled"]
readonly attribute Promise<RTCIdentityAssertion> peerIdentity; readonly attribute Promise<RTCIdentityAssertion> peerIdentity;
@ -160,6 +170,7 @@ interface RTCPeerConnection : EventTarget {
attribute EventHandler ontrack; // replaces onaddtrack and onaddstream. attribute EventHandler ontrack; // replaces onaddtrack and onaddstream.
attribute EventHandler oniceconnectionstatechange; attribute EventHandler oniceconnectionstatechange;
attribute EventHandler onicegatheringstatechange; attribute EventHandler onicegatheringstatechange;
attribute EventHandler onconnectionstatechange;
Promise<RTCStatsReport> getStats (optional MediaStreamTrack? selector = null); Promise<RTCStatsReport> getStats (optional MediaStreamTrack? selector = null);

Просмотреть файл

@ -16,7 +16,8 @@
enum RTCLifecycleEvent { enum RTCLifecycleEvent {
"initialized", "initialized",
"icegatheringstatechange", "icegatheringstatechange",
"iceconnectionstatechange" "iceconnectionstatechange",
"connectionstatechange",
}; };
callback PeerConnectionLifecycleCallback = undefined (RTCPeerConnection pc, callback PeerConnectionLifecycleCallback = undefined (RTCPeerConnection pc,