diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-13 15:05:36 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-14 10:33:47 +0000 |
commit | e684a3455bcc29a6e3e66a004e352dea4e1141e7 (patch) | |
tree | d55b4003bde34d7d05f558f02cfd82b2a66a7aac /chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc | |
parent | 2b94bfe47ccb6c08047959d1c26e392919550e86 (diff) | |
download | qtwebengine-chromium-e684a3455bcc29a6e3e66a004e352dea4e1141e7.tar.gz |
BASELINE: Update Chromium to 72.0.3626.110 and Ninja to 1.9.0
Change-Id: Ic57220b00ecc929a893c91f5cc552f5d3e99e922
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc | 907 |
1 files changed, 646 insertions, 261 deletions
diff --git a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc index 1072ca64219..e21602e3d2a 100644 --- a/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc +++ b/chromium/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc @@ -80,6 +80,7 @@ #include "third_party/blink/renderer/modules/mediastream/media_constraints_impl.h" #include "third_party/blink/renderer/modules/mediastream/media_stream.h" #include "third_party/blink/renderer/modules/mediastream/media_stream_event.h" +#include "third_party/blink/renderer/modules/mediastream/user_media_controller.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_answer_options.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_configuration.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h" @@ -113,6 +114,7 @@ #include "third_party/blink/renderer/platform/peerconnection/rtc_answer_options_platform.h" #include "third_party/blink/renderer/platform/peerconnection/rtc_offer_options_platform.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/blink/renderer/platform/wtf/time.h" #include "third_party/webrtc/api/jsep.h" #include "third_party/webrtc/api/peerconnectioninterface.h" @@ -176,34 +178,34 @@ bool CallErrorCallbackIfSignalingStateClosed( bool IsIceCandidateMissingSdp( const RTCIceCandidateInitOrRTCIceCandidate& candidate) { if (candidate.IsRTCIceCandidateInit()) { - const RTCIceCandidateInit& ice_candidate_init = + const RTCIceCandidateInit* ice_candidate_init = candidate.GetAsRTCIceCandidateInit(); - return !ice_candidate_init.hasSdpMid() && - !ice_candidate_init.hasSdpMLineIndex(); + return !ice_candidate_init->hasSdpMid() && + !ice_candidate_init->hasSdpMLineIndex(); } DCHECK(candidate.IsRTCIceCandidate()); return false; } -WebRTCOfferOptions ConvertToWebRTCOfferOptions(const RTCOfferOptions& options) { +WebRTCOfferOptions ConvertToWebRTCOfferOptions(const RTCOfferOptions* options) { return WebRTCOfferOptions(RTCOfferOptionsPlatform::Create( - options.hasOfferToReceiveVideo() - ? std::max(options.offerToReceiveVideo(), 0) + options->hasOfferToReceiveVideo() + ? std::max(options->offerToReceiveVideo(), 0) : -1, - options.hasOfferToReceiveAudio() - ? std::max(options.offerToReceiveAudio(), 0) + options->hasOfferToReceiveAudio() + ? std::max(options->offerToReceiveAudio(), 0) : -1, - options.hasVoiceActivityDetection() ? options.voiceActivityDetection() - : true, - options.hasIceRestart() ? options.iceRestart() : false)); + options->hasVoiceActivityDetection() ? options->voiceActivityDetection() + : true, + options->hasIceRestart() ? options->iceRestart() : false)); } WebRTCAnswerOptions ConvertToWebRTCAnswerOptions( - const RTCAnswerOptions& options) { + const RTCAnswerOptions* options) { return WebRTCAnswerOptions(RTCAnswerOptionsPlatform::Create( - options.hasVoiceActivityDetection() ? options.voiceActivityDetection() - : true)); + options->hasVoiceActivityDetection() ? options->voiceActivityDetection() + : true)); } scoped_refptr<WebRTCICECandidate> ConvertToWebRTCIceCandidate( @@ -211,18 +213,18 @@ scoped_refptr<WebRTCICECandidate> ConvertToWebRTCIceCandidate( const RTCIceCandidateInitOrRTCIceCandidate& candidate) { DCHECK(!candidate.IsNull()); if (candidate.IsRTCIceCandidateInit()) { - const RTCIceCandidateInit& ice_candidate_init = + const RTCIceCandidateInit* ice_candidate_init = candidate.GetAsRTCIceCandidateInit(); // TODO(guidou): Change default value to -1. crbug.com/614958. unsigned short sdp_m_line_index = 0; - if (ice_candidate_init.hasSdpMLineIndex()) { - sdp_m_line_index = ice_candidate_init.sdpMLineIndex(); + if (ice_candidate_init->hasSdpMLineIndex()) { + sdp_m_line_index = ice_candidate_init->sdpMLineIndex(); } else { UseCounter::Count(context, WebFeature::kRTCIceCandidateDefaultSdpMLineIndex); } - return WebRTCICECandidate::Create(ice_candidate_init.candidate(), - ice_candidate_init.sdpMid(), + return WebRTCICECandidate::Create(ice_candidate_init->candidate(), + ice_candidate_init->sdpMid(), sdp_m_line_index); } @@ -238,14 +240,14 @@ enum SdpSemanticRequested { }; SdpSemanticRequested GetSdpSemanticRequested( - const blink::RTCConfiguration& configuration) { - if (!configuration.hasSdpSemantics()) { + const blink::RTCConfiguration* configuration) { + if (!configuration->hasSdpSemantics()) { return kSdpSemanticRequestedDefault; } - if (configuration.sdpSemantics() == "plan-b") { + if (configuration->sdpSemantics() == "plan-b") { return kSdpSemanticRequestedPlanB; } - if (configuration.sdpSemantics() == "unified-plan") { + if (configuration->sdpSemantics() == "unified-plan") { return kSdpSemanticRequestedUnifiedPlan; } @@ -268,7 +270,8 @@ class WebRTCCertificateObserver : public WebRTCCertificateCallback { : resolver_(resolver) {} void OnSuccess(rtc::scoped_refptr<rtc::RTCCertificate> certificate) override { - resolver_->Resolve(new RTCCertificate(std::move(certificate))); + resolver_->Resolve( + MakeGarbageCollected<RTCCertificate>(std::move(certificate))); } void OnError() override { resolver_->Reject(); } @@ -286,45 +289,45 @@ webrtc::PeerConnectionInterface::IceTransportsType IceTransportPolicyFromString( webrtc::PeerConnectionInterface::RTCConfiguration ParseConfiguration( ExecutionContext* context, - const RTCConfiguration& configuration, + const RTCConfiguration* configuration, ExceptionState& exception_state) { DCHECK(context); webrtc::PeerConnectionInterface::RTCConfiguration web_configuration; - if (configuration.hasIceTransportPolicy()) { + if (configuration->hasIceTransportPolicy()) { UseCounter::Count(context, WebFeature::kRTCConfigurationIceTransportPolicy); web_configuration.type = - IceTransportPolicyFromString(configuration.iceTransportPolicy()); - } else if (configuration.hasIceTransports()) { + IceTransportPolicyFromString(configuration->iceTransportPolicy()); + } else if (configuration->hasIceTransports()) { UseCounter::Count(context, WebFeature::kRTCConfigurationIceTransports); web_configuration.type = - IceTransportPolicyFromString(configuration.iceTransports()); + IceTransportPolicyFromString(configuration->iceTransports()); } - if (configuration.bundlePolicy() == "max-compat") { + if (configuration->bundlePolicy() == "max-compat") { web_configuration.bundle_policy = webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat; - } else if (configuration.bundlePolicy() == "max-bundle") { + } else if (configuration->bundlePolicy() == "max-bundle") { web_configuration.bundle_policy = webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle; } else { - DCHECK_EQ(configuration.bundlePolicy(), "balanced"); + DCHECK_EQ(configuration->bundlePolicy(), "balanced"); } - if (configuration.rtcpMuxPolicy() == "negotiate") { + if (configuration->rtcpMuxPolicy() == "negotiate") { web_configuration.rtcp_mux_policy = webrtc::PeerConnectionInterface::kRtcpMuxPolicyNegotiate; Deprecation::CountDeprecation(context, WebFeature::kRtcpMuxPolicyNegotiate); } else { - DCHECK_EQ(configuration.rtcpMuxPolicy(), "require"); + DCHECK_EQ(configuration->rtcpMuxPolicy(), "require"); } - if (configuration.hasSdpSemantics()) { - if (configuration.sdpSemantics() == "plan-b") { + if (configuration->hasSdpSemantics()) { + if (configuration->sdpSemantics() == "plan-b") { web_configuration.sdp_semantics = webrtc::SdpSemantics::kPlanB; } else { - DCHECK_EQ(configuration.sdpSemantics(), "unified-plan"); + DCHECK_EQ(configuration->sdpSemantics(), "unified-plan"); web_configuration.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; } } else { @@ -340,29 +343,29 @@ webrtc::PeerConnectionInterface::RTCConfiguration ParseConfiguration( } } - if (configuration.hasIceServers()) { + if (configuration->hasIceServers()) { std::vector<webrtc::PeerConnectionInterface::IceServer> ice_servers; - for (const RTCIceServer& ice_server : configuration.iceServers()) { + for (const RTCIceServer* ice_server : configuration->iceServers()) { Vector<String> url_strings; - if (ice_server.hasURLs()) { + if (ice_server->hasURLs()) { UseCounter::Count(context, WebFeature::kRTCIceServerURLs); - const StringOrStringSequence& urls = ice_server.urls(); + const StringOrStringSequence& urls = ice_server->urls(); if (urls.IsString()) { url_strings.push_back(urls.GetAsString()); } else { DCHECK(urls.IsStringSequence()); url_strings = urls.GetAsStringSequence(); } - } else if (ice_server.hasURL()) { + } else if (ice_server->hasURL()) { UseCounter::Count(context, WebFeature::kRTCIceServerURL); - url_strings.push_back(ice_server.url()); + url_strings.push_back(ice_server->url()); } else { exception_state.ThrowTypeError("Malformed RTCIceServer"); return {}; } - String username = ice_server.username(); - String credential = ice_server.credential(); + String username = ice_server->username(); + String credential = ice_server->credential(); for (const String& url_string : url_strings) { KURL url(NullURL(), url_string); @@ -399,19 +402,38 @@ webrtc::PeerConnectionInterface::RTCConfiguration ParseConfiguration( web_configuration.servers = ice_servers; } - if (configuration.hasCertificates()) { + if (configuration->hasCertificates()) { const HeapVector<Member<RTCCertificate>>& certificates = - configuration.certificates(); + configuration->certificates(); std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> certificates_copy( certificates.size()); - for (size_t i = 0; i < certificates.size(); ++i) { + for (wtf_size_t i = 0; i < certificates.size(); ++i) { certificates_copy[i] = certificates[i]->Certificate(); } web_configuration.certificates = std::move(certificates_copy); } web_configuration.ice_candidate_pool_size = - configuration.iceCandidatePoolSize(); + configuration->iceCandidatePoolSize(); + + if (configuration->hasRtcAudioJitterBufferMaxPackets()) { + UseCounter::Count(context, WebFeature::kRTCMaxAudioBufferSize); + web_configuration.audio_jitter_buffer_max_packets = + static_cast<int>(configuration->rtcAudioJitterBufferMaxPackets()); + } + + if (configuration->hasRtcAudioJitterBufferFastAccelerate()) { + UseCounter::Count(context, WebFeature::kRTCMaxAudioBufferSize); + web_configuration.audio_jitter_buffer_fast_accelerate = + configuration->hasRtcAudioJitterBufferFastAccelerate(); + } + + if (configuration->hasRtcAudioJitterBufferMinDelayMs()) { + UseCounter::Count(context, WebFeature::kRTCMaxAudioBufferSize); + web_configuration.audio_jitter_buffer_min_delay_ms = + static_cast<int>(configuration->rtcAudioJitterBufferMinDelayMs()); + } + return web_configuration; } @@ -461,22 +483,24 @@ bool FingerprintMismatch(String old_sdp, String new_sdp) { // It's impossible to generate a valid fingerprint without createOffer // or createAnswer, so this only applies when there are no fingerprints. // This is allowed. - const size_t new_fingerprint_pos = new_sdp.Find("\na=fingerprint:"); + const wtf_size_t new_fingerprint_pos = new_sdp.Find("\na=fingerprint:"); if (new_fingerprint_pos == kNotFound) { return false; } // Look for fingerprint having been added. Not allowed. - const size_t old_fingerprint_pos = old_sdp.Find("\na=fingerprint:"); + const wtf_size_t old_fingerprint_pos = old_sdp.Find("\na=fingerprint:"); if (old_fingerprint_pos == kNotFound) { return true; } // Look for fingerprint being modified. Not allowed. Handle differences in // line endings ('\r\n' vs, '\n' when looking for the end of the fingerprint). - size_t old_fingerprint_end = old_sdp.Find("\r\n", old_fingerprint_pos + 1); + wtf_size_t old_fingerprint_end = + old_sdp.Find("\r\n", old_fingerprint_pos + 1); if (old_fingerprint_end == WTF::kNotFound) { old_fingerprint_end = old_sdp.Find("\n", old_fingerprint_pos + 1); } - size_t new_fingerprint_end = new_sdp.Find("\r\n", new_fingerprint_pos + 1); + wtf_size_t new_fingerprint_end = + new_sdp.Find("\r\n", new_fingerprint_pos + 1); if (new_fingerprint_end == WTF::kNotFound) { new_fingerprint_end = new_sdp.Find("\n", new_fingerprint_pos + 1); } @@ -486,8 +510,94 @@ bool FingerprintMismatch(String old_sdp, String new_sdp) { new_fingerprint_end - new_fingerprint_pos); } +enum class SdpFormat { + kSimple, + kComplexPlanB, + kComplexUnifiedPlan, +}; + +base::Optional<SdpFormat> DeduceSdpFormat(const String& type, + const String& sdp) { + std::unique_ptr<webrtc::SessionDescriptionInterface> session_description( + webrtc::CreateSessionDescription(type.Utf8().data(), sdp.Utf8().data(), + nullptr)); + if (!session_description) + return base::nullopt; + size_t num_audio_mlines = 0u; + size_t num_video_mlines = 0u; + size_t num_audio_tracks = 0u; + size_t num_video_tracks = 0u; + for (const cricket::ContentInfo& content : + session_description->description()->contents()) { + cricket::MediaType media_type = content.media_description()->type(); + size_t num_tracks = std::max(static_cast<size_t>(1u), + content.media_description()->streams().size()); + if (media_type == cricket::MEDIA_TYPE_AUDIO) { + ++num_audio_mlines; + num_audio_tracks += num_tracks; + } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { + ++num_video_mlines; + num_video_tracks += num_tracks; + } + } + if (num_audio_mlines <= 1u && num_audio_tracks <= 1u && + num_video_mlines <= 1u && num_video_tracks <= 1u) { + return SdpFormat::kSimple; + } + if ((num_audio_mlines == 1u && num_audio_tracks > 1u) || + (num_video_mlines == 1u && num_video_tracks > 1u)) { + return SdpFormat::kComplexPlanB; + } + DCHECK(num_audio_mlines > 1u || num_audio_tracks > 1u || + num_video_mlines > 1u || num_video_tracks > 1u); + return SdpFormat::kComplexUnifiedPlan; +} + +RTCSetSessionDescriptionOperation GetRTCVoidRequestOperationType( + RTCPeerConnection::SetSdpOperationType operation, + const RTCSessionDescriptionInit& description) { + switch (operation) { + case RTCPeerConnection::SetSdpOperationType::kSetLocalDescription: + if (description.type() == "offer") + return RTCSetSessionDescriptionOperation::kSetLocalDescriptionOffer; + if (description.type() == "answer" || description.type() == "pranswer") + return RTCSetSessionDescriptionOperation::kSetLocalDescriptionAnswer; + return RTCSetSessionDescriptionOperation::kSetLocalDescriptionInvalidType; + case RTCPeerConnection::SetSdpOperationType::kSetRemoteDescription: + if (description.type() == "offer") + return RTCSetSessionDescriptionOperation::kSetRemoteDescriptionOffer; + if (description.type() == "answer" || description.type() == "pranswer") + return RTCSetSessionDescriptionOperation::kSetRemoteDescriptionAnswer; + return RTCSetSessionDescriptionOperation:: + kSetRemoteDescriptionInvalidType; + } +} + } // namespace +SdpUsageCategory DeduceSdpUsageCategory(const String& sdp_type, + const String& sdp, + bool sdp_semantics_specified, + webrtc::SdpSemantics sdp_semantics) { + auto sdp_format = DeduceSdpFormat(sdp_type, sdp); + if (!sdp_format) + return SdpUsageCategory::kUnknown; + switch (*sdp_format) { + case SdpFormat::kSimple: + return SdpUsageCategory::kSafe; + case SdpFormat::kComplexPlanB: + return (sdp_semantics_specified && + sdp_semantics == webrtc::SdpSemantics::kPlanB) + ? SdpUsageCategory::kSafe + : SdpUsageCategory::kUnsafe; + case SdpFormat::kComplexUnifiedPlan: + return (sdp_semantics_specified && + sdp_semantics == webrtc::SdpSemantics::kUnifiedPlan) + ? SdpUsageCategory::kSafe + : SdpUsageCategory::kUnsafe; + } +} + RTCPeerConnection::EventWrapper::EventWrapper(Event* event, BoolFunction function) : event_(event), setup_function_(std::move(function)) {} @@ -505,7 +615,7 @@ void RTCPeerConnection::EventWrapper::Trace(blink::Visitor* visitor) { RTCPeerConnection* RTCPeerConnection::Create( ExecutionContext* context, - const RTCConfiguration& rtc_configuration, + const RTCConfiguration* rtc_configuration, const Dictionary& media_constraints, ExceptionState& exception_state) { // Count number of PeerConnections that could potentially be impacted by CSP @@ -546,15 +656,15 @@ RTCPeerConnection* RTCPeerConnection::Create( } MediaErrorState media_error_state; - WebMediaConstraints constraints = MediaConstraintsImpl::Create( + WebMediaConstraints constraints = media_constraints_impl::Create( context, media_constraints, media_error_state); if (media_error_state.HadException()) { media_error_state.RaiseException(exception_state); return nullptr; } - RTCPeerConnection* peer_connection = new RTCPeerConnection( - context, std::move(configuration), rtc_configuration.hasSdpSemantics(), + RTCPeerConnection* peer_connection = MakeGarbageCollected<RTCPeerConnection>( + context, std::move(configuration), rtc_configuration->hasSdpSemantics(), constraints, exception_state); peer_connection->PauseIfNeeded(); if (exception_state.HadException()) @@ -576,8 +686,10 @@ RTCPeerConnection::RTCPeerConnection( : PausableObject(context), signaling_state_( webrtc::PeerConnectionInterface::SignalingState::kStable), - ice_gathering_state_(kICEGatheringStateNew), - ice_connection_state_(kICEConnectionStateNew), + ice_gathering_state_(webrtc::PeerConnectionInterface::kIceGatheringNew), + ice_connection_state_(webrtc::PeerConnectionInterface::kIceConnectionNew), + peer_connection_state_( + webrtc::PeerConnectionInterface::PeerConnectionState::kNew), // WebRTC spec specifies kNetworking as task source. // https://www.w3.org/TR/webrtc/#operation dispatch_scheduled_event_runner_( @@ -656,23 +768,51 @@ void RTCPeerConnection::Dispose() { // Promptly clears a raw reference from content/ to an on-heap object // so that content/ doesn't access it in a lazy sweeping phase. peer_handler_.reset(); + + // UMA for CallSetupStates. This metric is reported regardless of whether or + // not getUserMedia() has been called in this document. + UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.CallSetupState.OffererState", + call_setup_state_tracker_.offerer_state()); + UMA_HISTOGRAM_ENUMERATION( + "WebRTC.PeerConnection.CallSetupState.AnswererState", + call_setup_state_tracker_.answerer_state()); + UMA_HISTOGRAM_ENUMERATION( + "WebRTC.PeerConnection.CallSetupState.CallSetupState", + call_setup_state_tracker_.GetCallSetupState()); + // UMA for CallSetupStates only for documents that have performed + // getUserMedia(). This heuristic hints that the peer connection is likely + // used in a media/conferencing context, which is a use case that may be + // particularly sensitive to the Plan B vs Unified Plan switch. + if (call_setup_state_tracker_.document_uses_media()) { + UMA_HISTOGRAM_ENUMERATION( + "WebRTC.PeerConnection.CallSetupStateWithGum.OffererState", + call_setup_state_tracker_.offerer_state()); + UMA_HISTOGRAM_ENUMERATION( + "WebRTC.PeerConnection.CallSetupStateWithGum.AnswererState", + call_setup_state_tracker_.answerer_state()); + UMA_HISTOGRAM_ENUMERATION( + "WebRTC.PeerConnection.CallSetupStateWithGum.CallSetupState", + call_setup_state_tracker_.GetCallSetupState()); + } } ScriptPromise RTCPeerConnection::createOffer(ScriptState* script_state, - const RTCOfferOptions& options) { + const RTCOfferOptions* options) { if (signaling_state_ == webrtc::PeerConnectionInterface::SignalingState::kClosed) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError, kSignalingStateClosedMessage)); } - + call_setup_state_tracker_.NoteOffererStateEvent( + OffererState::kCreateOfferPending, HasDocumentMedia()); ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); RTCSessionDescriptionRequest* request = RTCSessionDescriptionRequestPromiseImpl::Create( - this, resolver, "RTCPeerConnection", "createOffer"); - if (options.hasOfferToReceiveAudio() || options.hasOfferToReceiveVideo()) { + RTCCreateSessionDescriptionOperation::kCreateOffer, this, resolver, + "RTCPeerConnection", "createOffer"); + if (options->hasOfferToReceiveAudio() || options->hasOfferToReceiveVideo()) { ExecutionContext* context = ExecutionContext::From(script_state); UseCounter::Count( context, @@ -700,9 +840,13 @@ ScriptPromise RTCPeerConnection::createOffer( ParseOfferOptions(rtc_offer_options, exception_state); if (exception_state.HadException()) return ScriptPromise(); + call_setup_state_tracker_.NoteOffererStateEvent( + OffererState::kCreateOfferPending, HasDocumentMedia()); RTCSessionDescriptionRequest* request = RTCSessionDescriptionRequestImpl::Create( - GetExecutionContext(), this, success_callback, error_callback); + GetExecutionContext(), + RTCCreateSessionDescriptionOperation::kCreateOffer, this, + success_callback, error_callback); if (offer_options) { if (offer_options->OfferToReceiveAudio() != -1 || @@ -717,7 +861,7 @@ ScriptPromise RTCPeerConnection::createOffer( peer_handler_->CreateOffer(request, WebRTCOfferOptions(offer_options)); } else { MediaErrorState media_error_state; - WebMediaConstraints constraints = MediaConstraintsImpl::Create( + WebMediaConstraints constraints = media_constraints_impl::Create( context, rtc_offer_options, media_error_state); // Report constraints parsing errors via the callback, but ignore // unknown/unsupported constraints as they would be silently discarded by @@ -745,7 +889,7 @@ ScriptPromise RTCPeerConnection::createOffer( } ScriptPromise RTCPeerConnection::createAnswer(ScriptState* script_state, - const RTCAnswerOptions& options) { + const RTCAnswerOptions* options) { if (signaling_state_ == webrtc::PeerConnectionInterface::SignalingState::kClosed) { return ScriptPromise::RejectWithDOMException( @@ -753,11 +897,14 @@ ScriptPromise RTCPeerConnection::createAnswer(ScriptState* script_state, kSignalingStateClosedMessage)); } + call_setup_state_tracker_.NoteAnswererStateEvent( + AnswererState::kCreateAnswerPending, HasDocumentMedia()); ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); RTCSessionDescriptionRequest* request = RTCSessionDescriptionRequestPromiseImpl::Create( - this, resolver, "RTCPeerConnection", "createAnswer"); + RTCCreateSessionDescriptionOperation::kCreateAnswer, this, resolver, + "RTCPeerConnection", "createAnswer"); peer_handler_->CreateAnswer(request, ConvertToWebRTCAnswerOptions(options)); return promise; } @@ -784,7 +931,7 @@ ScriptPromise RTCPeerConnection::createAnswer( return ScriptPromise::CastUndefined(script_state); MediaErrorState media_error_state; - WebMediaConstraints constraints = MediaConstraintsImpl::Create( + WebMediaConstraints constraints = media_constraints_impl::Create( context, media_constraints, media_error_state); // Report constraints parsing errors via the callback, but ignore // unknown/unsupported constraints as they would be silently discarded by @@ -797,16 +944,20 @@ ScriptPromise RTCPeerConnection::createAnswer( return ScriptPromise::CastUndefined(script_state); } + call_setup_state_tracker_.NoteAnswererStateEvent( + AnswererState::kCreateAnswerPending, HasDocumentMedia()); RTCSessionDescriptionRequest* request = RTCSessionDescriptionRequestImpl::Create( - GetExecutionContext(), this, success_callback, error_callback); + GetExecutionContext(), + RTCCreateSessionDescriptionOperation::kCreateAnswer, this, + success_callback, error_callback); peer_handler_->CreateAnswer(request, constraints); return ScriptPromise::CastUndefined(script_state); } DOMException* RTCPeerConnection::checkSdpForStateErrors( ExecutionContext* context, - const RTCSessionDescriptionInit& session_description_init, + const RTCSessionDescriptionInit* session_description_init, String* sdp) { if (signaling_state_ == webrtc::PeerConnectionInterface::SignalingState::kClosed) { @@ -814,11 +965,11 @@ DOMException* RTCPeerConnection::checkSdpForStateErrors( kSignalingStateClosedMessage); } - *sdp = session_description_init.sdp(); - if (session_description_init.type() == "offer") { + *sdp = session_description_init->sdp(); + if (session_description_init->type() == "offer") { if (sdp->IsNull() || sdp->IsEmpty()) { *sdp = last_offer_; - } else if (session_description_init.sdp() != last_offer_) { + } else if (session_description_init->sdp() != last_offer_) { if (FingerprintMismatch(last_offer_, *sdp)) { return DOMException::Create(DOMExceptionCode::kInvalidModificationError, kModifiedSdpMessage); @@ -828,11 +979,11 @@ DOMException* RTCPeerConnection::checkSdpForStateErrors( // TODO(https://crbug.com/823036): Return failure for all modification. } } - } else if (session_description_init.type() == "answer" || - session_description_init.type() == "pranswer") { + } else if (session_description_init->type() == "answer" || + session_description_init->type() == "pranswer") { if (sdp->IsNull() || sdp->IsEmpty()) { *sdp = last_answer_; - } else if (session_description_init.sdp() != last_answer_) { + } else if (session_description_init->sdp() != last_answer_) { if (FingerprintMismatch(last_answer_, *sdp)) { return DOMException::Create(DOMExceptionCode::kInvalidModificationError, kModifiedSdpMessage); @@ -846,72 +997,208 @@ DOMException* RTCPeerConnection::checkSdpForStateErrors( return nullptr; } -bool RTCPeerConnection::ShouldShowComplexPlanBSdpWarning( - const RTCSessionDescriptionInit& session_description_init) const { - if (sdp_semantics_specified_) - return false; - if (!session_description_init.hasType() || !session_description_init.hasSdp()) - return false; - std::unique_ptr<webrtc::SessionDescriptionInterface> session_description( - webrtc::CreateSessionDescription( - session_description_init.type().Utf8().data(), - session_description_init.sdp().Utf8().data(), nullptr)); - if (!session_description) - return false; - size_t num_audio_mlines = 0u; - size_t num_video_mlines = 0u; - size_t num_audio_tracks = 0u; - size_t num_video_tracks = 0u; - for (const cricket::ContentInfo& content : - session_description->description()->contents()) { - cricket::MediaType media_type = content.media_description()->type(); - size_t num_tracks = std::max(static_cast<size_t>(1u), - content.media_description()->streams().size()); - if (media_type == cricket::MEDIA_TYPE_AUDIO) { - ++num_audio_mlines; - num_audio_tracks += num_tracks; - } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { - ++num_video_mlines; - num_video_tracks += num_tracks; - } +base::Optional<ComplexSdpCategory> RTCPeerConnection::CheckForComplexSdp( + const RTCSessionDescriptionInit* session_description_init) const { + if (!session_description_init->hasType() || + !session_description_init->hasSdp()) + return base::nullopt; + + base::Optional<SdpFormat> sdp_format = DeduceSdpFormat( + session_description_init->type(), session_description_init->sdp()); + if (!sdp_format) { + return sdp_semantics_specified_ + ? ComplexSdpCategory::kErrorExplicitSemantics + : ComplexSdpCategory::kErrorImplicitSemantics; } - return (num_audio_mlines == 1u && num_audio_tracks > 1u) || - (num_video_mlines == 1u && num_video_tracks > 1u); + + if (*sdp_format == SdpFormat::kComplexPlanB) { + return sdp_semantics_specified_ + ? ComplexSdpCategory::kPlanBExplicitSemantics + : ComplexSdpCategory::kPlanBImplicitSemantics; + } else if (*sdp_format == SdpFormat::kComplexUnifiedPlan) { + return sdp_semantics_specified_ + ? ComplexSdpCategory::kUnifiedPlanExplicitSemantics + : ComplexSdpCategory::kUnifiedPlanImplicitSemantics; + } + + return base::nullopt; } -ScriptPromise RTCPeerConnection::setLocalDescription( - ScriptState* script_state, - const RTCSessionDescriptionInit& session_description_init) { - if (ShouldShowComplexPlanBSdpWarning(session_description_init)) { +void RTCPeerConnection::MaybeWarnAboutUnsafeSdp( + const RTCSessionDescriptionInit* session_description_init) const { + base::Optional<ComplexSdpCategory> complex_sdp_category = + CheckForComplexSdp(session_description_init); + if (!complex_sdp_category) + return; + + Document* document = To<Document>(GetExecutionContext()); + RTCPeerConnectionController::From(*document).MaybeReportComplexSdp( + *complex_sdp_category); + + if (*complex_sdp_category == ComplexSdpCategory::kPlanBImplicitSemantics) { Deprecation::CountDeprecation( GetExecutionContext(), WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics); } +} + +const CallSetupStateTracker& RTCPeerConnection::call_setup_state_tracker() + const { + return call_setup_state_tracker_; +} + +void RTCPeerConnection::NoteCallSetupStateEventPending( + RTCPeerConnection::SetSdpOperationType operation, + const RTCSessionDescriptionInit& description) { + switch (operation) { + case RTCPeerConnection::SetSdpOperationType::kSetLocalDescription: + if (description.type() == "offer") { + call_setup_state_tracker_.NoteOffererStateEvent( + OffererState::kSetLocalOfferPending, HasDocumentMedia()); + } else if (description.type() == "answer" || + description.type() == "pranswer") { + call_setup_state_tracker_.NoteAnswererStateEvent( + AnswererState::kSetLocalAnswerPending, HasDocumentMedia()); + } + break; + case RTCPeerConnection::SetSdpOperationType::kSetRemoteDescription: + if (description.type() == "offer") { + call_setup_state_tracker_.NoteAnswererStateEvent( + AnswererState::kSetRemoteOfferPending, HasDocumentMedia()); + } else if (description.type() == "answer" || + description.type() == "pranswer") { + call_setup_state_tracker_.NoteOffererStateEvent( + OffererState::kSetRemoteAnswerPending, HasDocumentMedia()); + } + break; + } +} + +void RTCPeerConnection::NoteSessionDescriptionRequestCompleted( + RTCCreateSessionDescriptionOperation operation, + bool success) { + switch (operation) { + case RTCCreateSessionDescriptionOperation::kCreateOffer: + call_setup_state_tracker_.NoteOffererStateEvent( + success ? OffererState::kCreateOfferResolved + : OffererState::kCreateOfferRejected, + HasDocumentMedia()); + return; + case RTCCreateSessionDescriptionOperation::kCreateAnswer: + call_setup_state_tracker_.NoteAnswererStateEvent( + success ? AnswererState::kCreateAnswerResolved + : AnswererState::kCreateAnswerRejected, + HasDocumentMedia()); + return; + } +} + +void RTCPeerConnection::NoteVoidRequestCompleted( + RTCSetSessionDescriptionOperation operation, + bool success) { + switch (operation) { + case RTCSetSessionDescriptionOperation::kSetLocalDescriptionOffer: + call_setup_state_tracker_.NoteOffererStateEvent( + success ? OffererState::kSetLocalOfferResolved + : OffererState::kSetLocalOfferRejected, + HasDocumentMedia()); + break; + case RTCSetSessionDescriptionOperation::kSetLocalDescriptionAnswer: + call_setup_state_tracker_.NoteAnswererStateEvent( + success ? AnswererState::kSetLocalAnswerResolved + : AnswererState::kSetLocalAnswerRejected, + HasDocumentMedia()); + break; + case RTCSetSessionDescriptionOperation::kSetRemoteDescriptionOffer: + call_setup_state_tracker_.NoteAnswererStateEvent( + success ? AnswererState::kSetRemoteOfferResolved + : AnswererState::kSetRemoteOfferRejected, + HasDocumentMedia()); + break; + case RTCSetSessionDescriptionOperation::kSetRemoteDescriptionAnswer: + call_setup_state_tracker_.NoteOffererStateEvent( + success ? OffererState::kSetRemoteAnswerResolved + : OffererState::kSetRemoteAnswerRejected, + HasDocumentMedia()); + break; + case RTCSetSessionDescriptionOperation::kSetLocalDescriptionInvalidType: + case RTCSetSessionDescriptionOperation::kSetRemoteDescriptionInvalidType: + break; + } +} + +bool RTCPeerConnection::HasDocumentMedia() const { + UserMediaController* user_media_controller = UserMediaController::From( + To<Document>(GetExecutionContext())->GetFrame()); + return user_media_controller && + user_media_controller->HasRequestedUserMedia(); +} + +void RTCPeerConnection::ReportSetSdpUsage( + SetSdpOperationType operation_type, + const RTCSessionDescriptionInit* session_description_init) const { + SdpUsageCategory sdp_usage = DeduceSdpUsageCategory( + session_description_init->type(), session_description_init->sdp(), + sdp_semantics_specified_, sdp_semantics_); + if (session_description_init->type() == "offer") { + switch (operation_type) { + case SetSdpOperationType::kSetLocalDescription: + UMA_HISTOGRAM_ENUMERATION( + "WebRTC.PeerConnection.SdpComplexUsage.SetLocalOffer", sdp_usage); + break; + case SetSdpOperationType::kSetRemoteDescription: + UMA_HISTOGRAM_ENUMERATION( + "WebRTC.PeerConnection.SdpComplexUsage.SetRemoteOffer", sdp_usage); + break; + } + } else if (session_description_init->type() == "answer" || + session_description_init->type() == "pranswer") { + switch (operation_type) { + case SetSdpOperationType::kSetLocalDescription: + UMA_HISTOGRAM_ENUMERATION( + "WebRTC.PeerConnection.SdpComplexUsage.SetLocalAnswer", sdp_usage); + break; + case SetSdpOperationType::kSetRemoteDescription: + UMA_HISTOGRAM_ENUMERATION( + "WebRTC.PeerConnection.SdpComplexUsage.SetRemoteAnswer", sdp_usage); + break; + } + } +} + +ScriptPromise RTCPeerConnection::setLocalDescription( + ScriptState* script_state, + const RTCSessionDescriptionInit* session_description_init) { + MaybeWarnAboutUnsafeSdp(session_description_init); + ReportSetSdpUsage(SetSdpOperationType::kSetLocalDescription, + session_description_init); String sdp; DOMException* exception = checkSdpForStateErrors( ExecutionContext::From(script_state), session_description_init, &sdp); if (exception) { return ScriptPromise::RejectWithDOMException(script_state, exception); } + NoteCallSetupStateEventPending(SetSdpOperationType::kSetLocalDescription, + *session_description_init); ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); RTCVoidRequest* request = RTCVoidRequestPromiseImpl::Create( + GetRTCVoidRequestOperationType(SetSdpOperationType::kSetLocalDescription, + *session_description_init), this, resolver, "RTCPeerConnection", "setLocalDescription"); peer_handler_->SetLocalDescription( - request, WebRTCSessionDescription(session_description_init.type(), sdp)); + request, WebRTCSessionDescription(session_description_init->type(), sdp)); return promise; } ScriptPromise RTCPeerConnection::setLocalDescription( ScriptState* script_state, - const RTCSessionDescriptionInit& session_description_init, + const RTCSessionDescriptionInit* session_description_init, V8VoidFunction* success_callback, V8RTCPeerConnectionErrorCallback* error_callback) { - if (ShouldShowComplexPlanBSdpWarning(session_description_init)) { - Deprecation::CountDeprecation( - GetExecutionContext(), - WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics); - } + MaybeWarnAboutUnsafeSdp(session_description_init); + ReportSetSdpUsage(SetSdpOperationType::kSetLocalDescription, + session_description_init); ExecutionContext* context = ExecutionContext::From(script_state); if (success_callback && error_callback) { UseCounter::Count( @@ -939,11 +1226,16 @@ ScriptPromise RTCPeerConnection::setLocalDescription( return ScriptPromise::CastUndefined(script_state); } + NoteCallSetupStateEventPending(SetSdpOperationType::kSetLocalDescription, + *session_description_init); RTCVoidRequest* request = RTCVoidRequestImpl::Create( - GetExecutionContext(), this, success_callback, error_callback); + GetExecutionContext(), + GetRTCVoidRequestOperationType(SetSdpOperationType::kSetLocalDescription, + *session_description_init), + this, success_callback, error_callback); peer_handler_->SetLocalDescription( - request, WebRTCSessionDescription(session_description_init.type(), - session_description_init.sdp())); + request, WebRTCSessionDescription(session_description_init->type(), + session_description_init->sdp())); return ScriptPromise::CastUndefined(script_state); } @@ -976,12 +1268,10 @@ RTCSessionDescription* RTCPeerConnection::pendingLocalDescription() { ScriptPromise RTCPeerConnection::setRemoteDescription( ScriptState* script_state, - const RTCSessionDescriptionInit& session_description_init) { - if (ShouldShowComplexPlanBSdpWarning(session_description_init)) { - Deprecation::CountDeprecation( - GetExecutionContext(), - WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics); - } + const RTCSessionDescriptionInit* session_description_init) { + MaybeWarnAboutUnsafeSdp(session_description_init); + ReportSetSdpUsage(SetSdpOperationType::kSetRemoteDescription, + session_description_init); if (signaling_state_ == webrtc::PeerConnectionInterface::SignalingState::kClosed) { return ScriptPromise::RejectWithDOMException( @@ -989,26 +1279,28 @@ ScriptPromise RTCPeerConnection::setRemoteDescription( kSignalingStateClosedMessage)); } + NoteCallSetupStateEventPending(SetSdpOperationType::kSetRemoteDescription, + *session_description_init); ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); RTCVoidRequest* request = RTCVoidRequestPromiseImpl::Create( + GetRTCVoidRequestOperationType(SetSdpOperationType::kSetRemoteDescription, + *session_description_init), this, resolver, "RTCPeerConnection", "setRemoteDescription"); peer_handler_->SetRemoteDescription( - request, WebRTCSessionDescription(session_description_init.type(), - session_description_init.sdp())); + request, WebRTCSessionDescription(session_description_init->type(), + session_description_init->sdp())); return promise; } ScriptPromise RTCPeerConnection::setRemoteDescription( ScriptState* script_state, - const RTCSessionDescriptionInit& session_description_init, + const RTCSessionDescriptionInit* session_description_init, V8VoidFunction* success_callback, V8RTCPeerConnectionErrorCallback* error_callback) { - if (ShouldShowComplexPlanBSdpWarning(session_description_init)) { - Deprecation::CountDeprecation( - GetExecutionContext(), - WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics); - } + MaybeWarnAboutUnsafeSdp(session_description_init); + ReportSetSdpUsage(SetSdpOperationType::kSetRemoteDescription, + session_description_init); ExecutionContext* context = ExecutionContext::From(script_state); if (success_callback && error_callback) { UseCounter::Count( @@ -1030,11 +1322,16 @@ ScriptPromise RTCPeerConnection::setRemoteDescription( if (CallErrorCallbackIfSignalingStateClosed(signaling_state_, error_callback)) return ScriptPromise::CastUndefined(script_state); + NoteCallSetupStateEventPending(SetSdpOperationType::kSetRemoteDescription, + *session_description_init); RTCVoidRequest* request = RTCVoidRequestImpl::Create( - GetExecutionContext(), this, success_callback, error_callback); + GetExecutionContext(), + GetRTCVoidRequestOperationType(SetSdpOperationType::kSetRemoteDescription, + *session_description_init), + this, success_callback, error_callback); peer_handler_->SetRemoteDescription( - request, WebRTCSessionDescription(session_description_init.type(), - session_description_init.sdp())); + request, WebRTCSessionDescription(session_description_init->type(), + session_description_init->sdp())); return ScriptPromise::CastUndefined(script_state); } @@ -1065,15 +1362,17 @@ RTCSessionDescription* RTCPeerConnection::pendingRemoteDescription() { return RTCSessionDescription::Create(web_session_description); } -void RTCPeerConnection::getConfiguration(RTCConfiguration& result) { +RTCConfiguration* RTCPeerConnection::getConfiguration( + ScriptState* script_state) const { + RTCConfiguration* result = RTCConfiguration::Create(); const auto& webrtc_configuration = peer_handler_->GetConfiguration(); switch (webrtc_configuration.type) { case webrtc::PeerConnectionInterface::kRelay: - result.setIceTransportPolicy("relay"); + result->setIceTransportPolicy("relay"); break; case webrtc::PeerConnectionInterface::kAll: - result.setIceTransportPolicy("all"); + result->setIceTransportPolicy("all"); break; default: NOTREACHED(); @@ -1081,13 +1380,13 @@ void RTCPeerConnection::getConfiguration(RTCConfiguration& result) { switch (webrtc_configuration.bundle_policy) { case webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat: - result.setBundlePolicy("max-compat"); + result->setBundlePolicy("max-compat"); break; case webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle: - result.setBundlePolicy("max-bundle"); + result->setBundlePolicy("max-bundle"); break; case webrtc::PeerConnectionInterface::kBundlePolicyBalanced: - result.setBundlePolicy("balanced"); + result->setBundlePolicy("balanced"); break; default: NOTREACHED(); @@ -1095,10 +1394,10 @@ void RTCPeerConnection::getConfiguration(RTCConfiguration& result) { switch (webrtc_configuration.rtcp_mux_policy) { case webrtc::PeerConnectionInterface::kRtcpMuxPolicyNegotiate: - result.setRtcpMuxPolicy("negotiate"); + result->setRtcpMuxPolicy("negotiate"); break; case webrtc::PeerConnectionInterface::kRtcpMuxPolicyRequire: - result.setRtcpMuxPolicy("require"); + result->setRtcpMuxPolicy("require"); break; default: NOTREACHED(); @@ -1106,50 +1405,69 @@ void RTCPeerConnection::getConfiguration(RTCConfiguration& result) { switch (webrtc_configuration.sdp_semantics) { case webrtc::SdpSemantics::kPlanB: - result.setSdpSemantics("plan-b"); + result->setSdpSemantics("plan-b"); break; case webrtc::SdpSemantics::kUnifiedPlan: - result.setSdpSemantics("unified-plan"); + result->setSdpSemantics("unified-plan"); break; default: NOTREACHED(); } - HeapVector<RTCIceServer> ice_servers; - ice_servers.ReserveCapacity(webrtc_configuration.servers.size()); + HeapVector<Member<RTCIceServer>> ice_servers; + ice_servers.ReserveCapacity( + SafeCast<wtf_size_t>(webrtc_configuration.servers.size())); for (const auto& webrtc_server : webrtc_configuration.servers) { - ice_servers.emplace_back(); - auto& ice_server = ice_servers.back(); + auto* ice_server = RTCIceServer::Create(); StringOrStringSequence urls; Vector<String> url_vector; - url_vector.ReserveCapacity(webrtc_server.urls.size()); + url_vector.ReserveCapacity(SafeCast<wtf_size_t>(webrtc_server.urls.size())); for (const auto& url : webrtc_server.urls) { url_vector.emplace_back(url.c_str()); } urls.SetStringSequence(std::move(url_vector)); - ice_server.setURLs(urls); - ice_server.setUsername(webrtc_server.username.c_str()); - ice_server.setCredential(webrtc_server.password.c_str()); + ice_server->setURLs(urls); + ice_server->setUsername(webrtc_server.username.c_str()); + ice_server->setCredential(webrtc_server.password.c_str()); + ice_servers.push_back(ice_server); } - result.setIceServers(ice_servers); + result->setIceServers(ice_servers); if (!webrtc_configuration.certificates.empty()) { HeapVector<blink::Member<RTCCertificate>> certificates; - certificates.ReserveCapacity(webrtc_configuration.certificates.size()); + certificates.ReserveCapacity( + SafeCast<wtf_size_t>(webrtc_configuration.certificates.size())); for (const auto& webrtc_certificate : webrtc_configuration.certificates) { - certificates.emplace_back(new RTCCertificate(webrtc_certificate)); + certificates.emplace_back( + MakeGarbageCollected<RTCCertificate>(webrtc_certificate)); } - result.setCertificates(certificates); + result->setCertificates(certificates); + } + + result->setIceCandidatePoolSize(webrtc_configuration.ice_candidate_pool_size); + + const auto* context = ExecutionContext::From(script_state); + if (origin_trials::RtcAudioJitterBufferMaxPacketsEnabled(context)) { + int audio_jitter_buffer_max_packets = + webrtc_configuration.audio_jitter_buffer_max_packets; + result->setRtcAudioJitterBufferMaxPackets( + static_cast<int32_t>(audio_jitter_buffer_max_packets)); + result->setRtcAudioJitterBufferFastAccelerate( + webrtc_configuration.audio_jitter_buffer_fast_accelerate); + int audio_jitter_buffer_min_delay_ms = + webrtc_configuration.audio_jitter_buffer_min_delay_ms; + result->setRtcAudioJitterBufferMinDelayMs( + static_cast<int32_t>(audio_jitter_buffer_min_delay_ms)); } - result.setIceCandidatePoolSize(webrtc_configuration.ice_candidate_pool_size); + return result; } void RTCPeerConnection::setConfiguration( ScriptState* script_state, - const RTCConfiguration& rtc_configuration, + const RTCConfiguration* rtc_configuration, ExceptionState& exception_state) { if (ThrowExceptionIfSignalingStateClosed(signaling_state_, exception_state)) return; @@ -1331,7 +1649,7 @@ ScriptPromise RTCPeerConnection::addIceCandidate( ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); RTCVoidRequest* request = RTCVoidRequestPromiseImpl::Create( - this, resolver, "RTCPeerConnection", "addIceCandidate"); + base::nullopt, this, resolver, "RTCPeerConnection", "addIceCandidate"); scoped_refptr<WebRTCICECandidate> web_candidate = ConvertToWebRTCIceCandidate( ExecutionContext::From(script_state), candidate); bool implemented = @@ -1363,8 +1681,9 @@ ScriptPromise RTCPeerConnection::addIceCandidate( return ScriptPromise(); } - RTCVoidRequest* request = RTCVoidRequestImpl::Create( - GetExecutionContext(), this, success_callback, error_callback); + RTCVoidRequest* request = + RTCVoidRequestImpl::Create(GetExecutionContext(), base::nullopt, this, + success_callback, error_callback); scoped_refptr<WebRTCICECandidate> web_candidate = ConvertToWebRTCIceCandidate( ExecutionContext::From(script_state), candidate); bool implemented = @@ -1400,11 +1719,11 @@ String RTCPeerConnection::signalingState() const { String RTCPeerConnection::iceGatheringState() const { switch (ice_gathering_state_) { - case kICEGatheringStateNew: + case webrtc::PeerConnectionInterface::kIceGatheringNew: return "new"; - case kICEGatheringStateGathering: + case webrtc::PeerConnectionInterface::kIceGatheringGathering: return "gathering"; - case kICEGatheringStateComplete: + case webrtc::PeerConnectionInterface::kIceGatheringComplete: return "complete"; } @@ -1413,20 +1732,48 @@ String RTCPeerConnection::iceGatheringState() const { } String RTCPeerConnection::iceConnectionState() const { + if (closed_) { + return "closed"; + } switch (ice_connection_state_) { - case kICEConnectionStateNew: + case webrtc::PeerConnectionInterface::kIceConnectionNew: return "new"; - case kICEConnectionStateChecking: + case webrtc::PeerConnectionInterface::kIceConnectionChecking: return "checking"; - case kICEConnectionStateConnected: + case webrtc::PeerConnectionInterface::kIceConnectionConnected: return "connected"; - case kICEConnectionStateCompleted: + case webrtc::PeerConnectionInterface::kIceConnectionCompleted: return "completed"; - case kICEConnectionStateFailed: + case webrtc::PeerConnectionInterface::kIceConnectionFailed: return "failed"; - case kICEConnectionStateDisconnected: + case webrtc::PeerConnectionInterface::kIceConnectionDisconnected: + return "disconnected"; + case webrtc::PeerConnectionInterface::kIceConnectionClosed: + return "closed"; + case webrtc::PeerConnectionInterface::kIceConnectionMax: + NOTREACHED(); + } + + NOTREACHED(); + return String(); +} + +String RTCPeerConnection::connectionState() const { + if (closed_) { + return "closed"; + } + switch (peer_connection_state_) { + case webrtc::PeerConnectionInterface::PeerConnectionState::kNew: + return "new"; + case webrtc::PeerConnectionInterface::PeerConnectionState::kConnecting: + return "connecting"; + case webrtc::PeerConnectionInterface::PeerConnectionState::kConnected: + return "connected"; + case webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected: return "disconnected"; - case kICEConnectionStateClosed: + case webrtc::PeerConnectionInterface::PeerConnectionState::kFailed: + return "failed"; + case webrtc::PeerConnectionInterface::PeerConnectionState::kClosed: return "closed"; } @@ -1443,8 +1790,8 @@ void RTCPeerConnection::addStream(ScriptState* script_state, if (!media_constraints.IsUndefinedOrNull()) { MediaErrorState media_error_state; WebMediaConstraints constraints = - MediaConstraintsImpl::Create(ExecutionContext::From(script_state), - media_constraints, media_error_state); + media_constraints_impl::Create(ExecutionContext::From(script_state), + media_constraints, media_error_state); if (media_error_state.HadException()) { media_error_state.RaiseException(exception_state); return; @@ -1479,7 +1826,7 @@ void RTCPeerConnection::removeStream(MediaStream* stream, } String RTCPeerConnection::id(ScriptState* script_state) const { - DCHECK(OriginTrials::RtcPeerConnectionIdEnabled( + DCHECK(origin_trials::RtcPeerConnectionIdEnabled( ExecutionContext::From(script_state))); return peer_handler_->Id(); } @@ -1633,8 +1980,8 @@ ScriptPromise RTCPeerConnection::PromiseBasedGetStats( ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise promise = resolver->Promise(); - peer_handler_->GetStats( - WebRTCStatsReportCallbackResolver::Create(resolver)); + peer_handler_->GetStats(WebRTCStatsReportCallbackResolver::Create(resolver), + GetRTCStatsFilter(script_state)); return promise; } @@ -1693,7 +2040,7 @@ const HeapVector<Member<RTCRtpReceiver>>& RTCPeerConnection::getReceivers() RTCRtpTransceiver* RTCPeerConnection::addTransceiver( const MediaStreamTrackOrString& track_or_kind, - const RTCRtpTransceiverInit& init, + const RTCRtpTransceiverInit* init, ExceptionState& exception_state) { if (sdp_semantics_ != webrtc::SdpSemantics::kUnifiedPlan) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, @@ -1760,7 +2107,7 @@ RTCRtpSender* RTCPeerConnection::addTrack(MediaStreamTrack* track, } WebVector<WebMediaStream> web_streams(streams.size()); - for (size_t i = 0; i < streams.size(); ++i) { + for (wtf_size_t i = 0; i < streams.size(); ++i) { web_streams[i] = streams[i]->Descriptor(); } webrtc::RTCErrorOr<std::unique_ptr<WebRTCRtpTransceiver>> @@ -1846,38 +2193,38 @@ void RTCPeerConnection::removeTrack(RTCRtpSender* sender, RTCDataChannel* RTCPeerConnection::createDataChannel( ScriptState* script_state, String label, - const RTCDataChannelInit& data_channel_dict, + const RTCDataChannelInit* data_channel_dict, ExceptionState& exception_state) { if (ThrowExceptionIfSignalingStateClosed(signaling_state_, exception_state)) return nullptr; WebRTCDataChannelInit init; - init.ordered = data_channel_dict.ordered(); + init.ordered = data_channel_dict->ordered(); ExecutionContext* context = ExecutionContext::From(script_state); // maxPacketLifeTime and maxRetransmitTime are two names for the same thing, // but maxPacketLifeTime is the standardized name so it takes precedence. - if (data_channel_dict.hasMaxPacketLifeTime()) { + if (data_channel_dict->hasMaxPacketLifeTime()) { UseCounter::Count( context, WebFeature::kRTCPeerConnectionCreateDataChannelMaxPacketLifeTime); - init.max_retransmit_time = data_channel_dict.maxPacketLifeTime(); - } else if (data_channel_dict.hasMaxRetransmitTime()) { + init.max_retransmit_time = data_channel_dict->maxPacketLifeTime(); + } else if (data_channel_dict->hasMaxRetransmitTime()) { Deprecation::CountDeprecation( context, WebFeature::kRTCDataChannelInitMaxRetransmitTime); UseCounter::Count( context, WebFeature::kRTCPeerConnectionCreateDataChannelMaxRetransmitTime); - init.max_retransmit_time = data_channel_dict.maxRetransmitTime(); + init.max_retransmit_time = data_channel_dict->maxRetransmitTime(); } - if (data_channel_dict.hasMaxRetransmits()) { + if (data_channel_dict->hasMaxRetransmits()) { UseCounter::Count( context, WebFeature::kRTCPeerConnectionCreateDataChannelMaxRetransmits); - init.max_retransmits = data_channel_dict.maxRetransmits(); + init.max_retransmits = data_channel_dict->maxRetransmits(); } - init.protocol = data_channel_dict.protocol(); - init.negotiated = data_channel_dict.negotiated(); - if (data_channel_dict.hasId()) - init.id = data_channel_dict.id(); + init.protocol = data_channel_dict->protocol(); + init.negotiated = data_channel_dict->negotiated(); + if (data_channel_dict->hasId()) + init.id = data_channel_dict->id(); RTCDataChannel* channel = RTCDataChannel::Create( GetExecutionContext(), peer_handler_.get(), label, init, exception_state); @@ -1959,7 +2306,8 @@ RTCRtpSender* RTCPeerConnection::CreateOrUpdateSender( RTCRtpSender* sender; if (sender_it == rtp_senders_.end()) { // Create new sender (with empty stream set). - sender = new RTCRtpSender(this, std::move(web_sender), kind, track, {}); + sender = MakeGarbageCollected<RTCRtpSender>( + this, std::move(web_sender), kind, track, MediaStreamVector()); rtp_senders_.push_back(sender); } else { // Update existing sender (not touching the stream set). @@ -1988,7 +2336,8 @@ RTCRtpReceiver* RTCPeerConnection::CreateOrUpdateReceiver( RTCRtpReceiver* receiver; if (receiver_it == rtp_receivers_.end()) { // Create new receiver. - receiver = new RTCRtpReceiver(std::move(web_receiver), track, {}); + receiver = MakeGarbageCollected<RTCRtpReceiver>(std::move(web_receiver), + track, MediaStreamVector()); // Receiving tracks should be muted by default. SetReadyState() propagates // the related state changes to ensure it is muted on all layers. It also // fires events - which is not desired - but because they fire synchronously @@ -2020,8 +2369,8 @@ RTCRtpTransceiver* RTCPeerConnection::CreateOrUpdateTransceiver( auto* transceiver_it = FindTransceiver(*web_transceiver); if (transceiver_it == transceivers_.end()) { // Create new tranceiver. - transceiver = new RTCRtpTransceiver(this, std::move(web_transceiver), - sender, receiver); + transceiver = MakeGarbageCollected<RTCRtpTransceiver>( + this, std::move(web_transceiver), sender, receiver); transceivers_.push_back(transceiver); } else { // Update existing transceiver. @@ -2080,10 +2429,16 @@ void RTCPeerConnection::RegisterTrack(MediaStreamTrack* track) { } void RTCPeerConnection::NoteSdpCreated(const RTCSessionDescription& desc) { + SdpUsageCategory sdp_usage = DeduceSdpUsageCategory( + desc.type(), desc.sdp(), sdp_semantics_specified_, sdp_semantics_); if (desc.type() == "offer") { last_offer_ = desc.sdp(); + UMA_HISTOGRAM_ENUMERATION( + "WebRTC.PeerConnection.SdpComplexUsage.CreateOffer", sdp_usage); } else if (desc.type() == "answer") { last_answer_ = desc.sdp(); + UMA_HISTOGRAM_ENUMERATION( + "WebRTC.PeerConnection.SdpComplexUsage.CreateAnswer", sdp_usage); } } @@ -2127,7 +2482,7 @@ void RTCPeerConnection::MaybeFireNegotiationNeeded() { if (!negotiation_needed_ || closed_) return; negotiation_needed_ = false; - DispatchEvent(*Event::Create(EventTypeNames::negotiationneeded)); + DispatchEvent(*Event::Create(event_type_names::kNegotiationneeded)); } void RTCPeerConnection::DidGenerateICECandidate( @@ -2147,20 +2502,27 @@ void RTCPeerConnection::DidChangeSignalingState( ChangeSignalingState(new_state, true); } -void RTCPeerConnection::DidChangeICEGatheringState( - ICEGatheringState new_state) { +void RTCPeerConnection::DidChangeIceGatheringState( + webrtc::PeerConnectionInterface::IceGatheringState new_state) { DCHECK(!closed_); DCHECK(GetExecutionContext()->IsContextThread()); ChangeIceGatheringState(new_state); } -void RTCPeerConnection::DidChangeICEConnectionState( - ICEConnectionState new_state) { +void RTCPeerConnection::DidChangeIceConnectionState( + webrtc::PeerConnectionInterface::IceConnectionState new_state) { DCHECK(!closed_); DCHECK(GetExecutionContext()->IsContextThread()); ChangeIceConnectionState(new_state); } +void RTCPeerConnection::DidChangePeerConnectionState( + webrtc::PeerConnectionInterface::PeerConnectionState new_state) { + DCHECK(!closed_); + DCHECK(GetExecutionContext()->IsContextThread()); + ChangePeerConnectionState(new_state); +} + void RTCPeerConnection::DidAddReceiverPlanB( std::unique_ptr<WebRTCRtpReceiver> web_receiver) { DCHECK(!closed_); @@ -2201,7 +2563,7 @@ void RTCPeerConnection::DidAddReceiverPlanB( std::move(audio_tracks), std::move(video_tracks)); // Schedule to fire "pc.onaddstream". ScheduleDispatchEvent( - MediaStreamEvent::Create(EventTypeNames::addstream, stream)); + MediaStreamEvent::Create(event_type_names::kAddstream, stream)); } else { // The stream already exists, add the track to it. // This will cause to schedule to fire "stream.onaddtrack". @@ -2210,11 +2572,11 @@ void RTCPeerConnection::DidAddReceiverPlanB( streams.push_back(stream); } DCHECK(FindReceiver(*web_receiver) == rtp_receivers_.end()); - RTCRtpReceiver* rtp_receiver = - new RTCRtpReceiver(std::move(web_receiver), track, streams); + RTCRtpReceiver* rtp_receiver = MakeGarbageCollected<RTCRtpReceiver>( + std::move(web_receiver), track, streams); rtp_receivers_.push_back(rtp_receiver); - ScheduleDispatchEvent( - new RTCTrackEvent(rtp_receiver, rtp_receiver->track(), streams, nullptr)); + ScheduleDispatchEvent(MakeGarbageCollected<RTCTrackEvent>( + rtp_receiver, rtp_receiver->track(), streams, nullptr)); } void RTCPeerConnection::DidRemoveReceiverPlanB( @@ -2244,7 +2606,7 @@ void RTCPeerConnection::DidRemoveReceiverPlanB( stream->StreamEnded(); stream->UnregisterObserver(this); ScheduleDispatchEvent( - MediaStreamEvent::Create(EventTypeNames::removestream, stream)); + MediaStreamEvent::Create(event_type_names::kRemovestream, stream)); } } @@ -2269,16 +2631,30 @@ void RTCPeerConnection::DidModifyTransceivers( RTCRtpTransceiver* transceiver = CreateOrUpdateTransceiver(std::move(web_transceiver)); - // The transceiver is now up-to-date. Compare before/after values of - // FiredDirectionHasRecv() and process the remote track if it changed. - if (is_remote_description && !previously_had_recv && - transceiver->FiredDirectionHasRecv()) { - ProcessAdditionOfRemoteTrack( - transceiver, transceiver->web_transceiver()->Receiver()->StreamIds(), - &add_list, &track_events); + size_t add_list_prev_size = add_list.size(); + // "Set the associated remote streams". + // https://w3c.github.io/webrtc-pc/#set-associated-remote-streams + SetAssociatedMediaStreams( + transceiver->receiver(), + transceiver->web_transceiver()->Receiver()->StreamIds(), &remove_list, + &add_list); + // The transceiver is now up-to-date. Check if the receiver's track is now + // considered added or removed (though a receiver's track is never truly + // removed). A track event indicates either that the track was "added" in + // the sense that FiredDirectionHasRecv() changed, or that a new remote + // stream was added containing the receiver's track. + if (is_remote_description && + ((!previously_had_recv && transceiver->FiredDirectionHasRecv()) || + add_list_prev_size != add_list.size())) { + // "Process the addition of a remote track". + // https://w3c.github.io/webrtc-pc/#process-remote-track-addition + track_events.push_back(transceiver); } if (previously_had_recv && !transceiver->FiredDirectionHasRecv()) { - ProcessRemovalOfRemoteTrack(transceiver, &remove_list, &mute_tracks); + // "Process the removal of a remote track". + // https://w3c.github.io/webrtc-pc/#process-remote-track-removal + if (!transceiver->receiver()->track()->muted()) + mute_tracks.push_back(transceiver->receiver()->track()); } } MediaStreamVector current_streams = getRemoteStreams(); @@ -2316,20 +2692,20 @@ void RTCPeerConnection::DidModifyTransceivers( // Legacy APIs: "pc.onaddstream" and "pc.onremovestream". for (const auto& current_stream : current_streams) { if (!previous_streams.Contains(current_stream)) { - ScheduleDispatchEvent( - MediaStreamEvent::Create(EventTypeNames::addstream, current_stream)); + ScheduleDispatchEvent(MediaStreamEvent::Create( + event_type_names::kAddstream, current_stream)); } } for (const auto& previous_stream : previous_streams) { if (!current_streams.Contains(previous_stream)) { ScheduleDispatchEvent(MediaStreamEvent::Create( - EventTypeNames::removestream, previous_stream)); + event_type_names::kRemovestream, previous_stream)); } } // Fire "pc.ontrack" synchronously. for (auto& transceiver : track_events) { - auto* track_event = new RTCTrackEvent( + auto* track_event = MakeGarbageCollected<RTCTrackEvent>( transceiver->receiver(), transceiver->receiver()->track(), transceiver->receiver()->streams(), transceiver); DispatchEvent(*track_event); @@ -2344,29 +2720,6 @@ void RTCPeerConnection::DidModifyTransceivers( } } -void RTCPeerConnection::ProcessAdditionOfRemoteTrack( - RTCRtpTransceiver* transceiver, - const WebVector<WebString>& stream_ids, - HeapVector<std::pair<Member<MediaStream>, Member<MediaStreamTrack>>>* - add_list, - HeapVector<Member<RTCRtpTransceiver>>* track_events) { - SetAssociatedMediaStreams(transceiver->receiver(), stream_ids, nullptr, - add_list); - track_events->push_back(transceiver); -} - -void RTCPeerConnection::ProcessRemovalOfRemoteTrack( - RTCRtpTransceiver* transceiver, - HeapVector<std::pair<Member<MediaStream>, Member<MediaStreamTrack>>>* - remove_list, - HeapVector<Member<MediaStreamTrack>>* mute_tracks) { - WebVector<WebString> stream_ids = {}; - SetAssociatedMediaStreams(transceiver->receiver(), stream_ids, remove_list, - nullptr); - if (!transceiver->receiver()->track()->muted()) - mute_tracks->push_back(transceiver->receiver()->track()); -} - void RTCPeerConnection::SetAssociatedMediaStreams( RTCRtpReceiver* receiver, const WebVector<WebString>& stream_ids, @@ -2421,7 +2774,7 @@ void RTCPeerConnection::DidAddRemoteDataChannel( RTCDataChannel* channel = RTCDataChannel::Create(GetExecutionContext(), base::WrapUnique(handler)); ScheduleDispatchEvent( - RTCDataChannelEvent::Create(EventTypeNames::datachannel, channel)); + RTCDataChannelEvent::Create(event_type_names::kDatachannel, channel)); has_data_channels_ = true; } @@ -2438,7 +2791,7 @@ void RTCPeerConnection::ReleasePeerConnectionHandler() { return; stopped_ = true; - ice_connection_state_ = kICEConnectionStateClosed; + ice_connection_state_ = webrtc::PeerConnectionInterface::kIceConnectionClosed; signaling_state_ = webrtc::PeerConnectionInterface::SignalingState::kClosed; dispatch_scheduled_event_runner_->Stop(); @@ -2455,7 +2808,7 @@ void RTCPeerConnection::ClosePeerConnection() { } const AtomicString& RTCPeerConnection::InterfaceName() const { - return EventTargetNames::RTCPeerConnection; + return event_target_names::kRTCPeerConnection; } ExecutionContext* RTCPeerConnection::GetExecutionContext() const { @@ -2482,7 +2835,7 @@ void RTCPeerConnection::ChangeSignalingState( if (signaling_state_ != webrtc::PeerConnectionInterface::SignalingState::kClosed) { signaling_state_ = signaling_state; - Event* event = Event::Create(EventTypeNames::signalingstatechange); + Event* event = Event::Create(event_type_names::kSignalingstatechange); if (dispatch_event_immediately) DispatchEvent(*event); else @@ -2491,13 +2844,15 @@ void RTCPeerConnection::ChangeSignalingState( } void RTCPeerConnection::ChangeIceGatheringState( - ICEGatheringState ice_gathering_state) { - if (ice_connection_state_ != kICEConnectionStateClosed) { + webrtc::PeerConnectionInterface::IceGatheringState ice_gathering_state) { + if (ice_connection_state_ != + webrtc::PeerConnectionInterface::kIceConnectionClosed) { ScheduleDispatchEvent( - Event::Create(EventTypeNames::icegatheringstatechange), + Event::Create(event_type_names::kIcegatheringstatechange), WTF::Bind(&RTCPeerConnection::SetIceGatheringState, WrapPersistent(this), ice_gathering_state)); - if (ice_gathering_state == kICEGatheringStateComplete) { + if (ice_gathering_state == + webrtc::PeerConnectionInterface::kIceGatheringComplete) { // If ICE gathering is completed, generate a null ICE candidate, to // signal end of candidates. ScheduleDispatchEvent(RTCPeerConnectionIceEvent::Create(nullptr)); @@ -2506,8 +2861,9 @@ void RTCPeerConnection::ChangeIceGatheringState( } bool RTCPeerConnection::SetIceGatheringState( - ICEGatheringState ice_gathering_state) { - if (ice_connection_state_ != kICEConnectionStateClosed && + webrtc::PeerConnectionInterface::IceGatheringState ice_gathering_state) { + if (ice_connection_state_ != + webrtc::PeerConnectionInterface::kIceConnectionClosed && ice_gathering_state_ != ice_gathering_state) { ice_gathering_state_ = ice_gathering_state; return true; @@ -2516,23 +2872,49 @@ bool RTCPeerConnection::SetIceGatheringState( } void RTCPeerConnection::ChangeIceConnectionState( - ICEConnectionState ice_connection_state) { - if (ice_connection_state_ != kICEConnectionStateClosed) { + webrtc::PeerConnectionInterface::IceConnectionState ice_connection_state) { + if (ice_connection_state_ != + webrtc::PeerConnectionInterface::kIceConnectionClosed) { ScheduleDispatchEvent( - Event::Create(EventTypeNames::iceconnectionstatechange), + Event::Create(event_type_names::kIceconnectionstatechange), WTF::Bind(&RTCPeerConnection::SetIceConnectionState, WrapPersistent(this), ice_connection_state)); } } bool RTCPeerConnection::SetIceConnectionState( - ICEConnectionState ice_connection_state) { - if (ice_connection_state_ != kICEConnectionStateClosed && + webrtc::PeerConnectionInterface::IceConnectionState ice_connection_state) { + if (ice_connection_state_ != + webrtc::PeerConnectionInterface::kIceConnectionClosed && ice_connection_state_ != ice_connection_state) { ice_connection_state_ = ice_connection_state; - if (ice_connection_state_ == kICEConnectionStateConnected) + if (ice_connection_state_ == + webrtc::PeerConnectionInterface::kIceConnectionConnected) RecordRapporMetrics(); + return true; + } + return false; +} + +void RTCPeerConnection::ChangePeerConnectionState( + webrtc::PeerConnectionInterface::PeerConnectionState + peer_connection_state) { + if (peer_connection_state_ != + webrtc::PeerConnectionInterface::PeerConnectionState::kClosed) { + ScheduleDispatchEvent( + Event::Create(event_type_names::kConnectionstatechange), + WTF::Bind(&RTCPeerConnection::SetPeerConnectionState, + WrapPersistent(this), peer_connection_state)); + } +} +bool RTCPeerConnection::SetPeerConnectionState( + webrtc::PeerConnectionInterface::PeerConnectionState + peer_connection_state) { + if (peer_connection_state_ != + webrtc::PeerConnectionInterface::PeerConnectionState::kClosed && + peer_connection_state_ != peer_connection_state) { + peer_connection_state_ = peer_connection_state; return true; } return false; @@ -2544,7 +2926,10 @@ void RTCPeerConnection::CloseInternal() { peer_handler_->Stop(); closed_ = true; - ChangeIceConnectionState(kICEConnectionStateClosed); + ChangeIceConnectionState( + webrtc::PeerConnectionInterface::kIceConnectionClosed); + SetPeerConnectionState( + webrtc::PeerConnectionInterface::PeerConnectionState::kClosed); ChangeSignalingState(webrtc::PeerConnectionInterface::SignalingState::kClosed, false); for (auto& transceiver : transceivers_) { @@ -2565,7 +2950,7 @@ void RTCPeerConnection::ScheduleDispatchEvent(Event* event) { void RTCPeerConnection::ScheduleDispatchEvent(Event* event, BoolFunction setup_function) { scheduled_events_.push_back( - new EventWrapper(event, std::move(setup_function))); + MakeGarbageCollected<EventWrapper>(event, std::move(setup_function))); dispatch_scheduled_event_runner_->RunAsync(); } |