Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(170)

Side by Side Diff: third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.cpp

Issue 2097563002: Split the mediastream module in Blink into mediastream and peerconnection (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Copy OWNERS file from mediastream/ to peerconnection/ Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * 3. Neither the name of Google Inc. nor the names of its contributors
15 * may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "modules/mediastream/RTCPeerConnection.h"
32
33 #include "bindings/core/v8/ArrayValue.h"
34 #include "bindings/core/v8/ExceptionMessages.h"
35 #include "bindings/core/v8/ExceptionState.h"
36 #include "bindings/core/v8/Microtask.h"
37 #include "bindings/core/v8/Nullable.h"
38 #include "bindings/core/v8/ScriptPromiseResolver.h"
39 #include "bindings/core/v8/ScriptState.h"
40 #include "bindings/core/v8/ScriptValue.h"
41 #include "bindings/core/v8/V8ThrowException.h"
42 #include "bindings/modules/v8/RTCIceCandidateInitOrRTCIceCandidate.h"
43 #include "bindings/modules/v8/V8RTCCertificate.h"
44 #include "core/dom/DOMException.h"
45 #include "core/dom/DOMTimeStamp.h"
46 #include "core/dom/Document.h"
47 #include "core/dom/ExceptionCode.h"
48 #include "core/dom/ExecutionContext.h"
49 #include "core/frame/LocalFrame.h"
50 #include "core/frame/UseCounter.h"
51 #include "core/html/VoidCallback.h"
52 #include "core/loader/FrameLoader.h"
53 #include "core/loader/FrameLoaderClient.h"
54 #include "modules/crypto/CryptoResultImpl.h"
55 #include "modules/mediastream/MediaConstraintsImpl.h"
56 #include "modules/mediastream/MediaStreamEvent.h"
57 #include "modules/mediastream/RTCAnswerOptions.h"
58 #include "modules/mediastream/RTCDTMFSender.h"
59 #include "modules/mediastream/RTCDataChannel.h"
60 #include "modules/mediastream/RTCDataChannelEvent.h"
61 #include "modules/mediastream/RTCIceCandidateEvent.h"
62 #include "modules/mediastream/RTCOfferOptions.h"
63 #include "modules/mediastream/RTCPeerConnectionErrorCallback.h"
64 #include "modules/mediastream/RTCSessionDescription.h"
65 #include "modules/mediastream/RTCSessionDescriptionCallback.h"
66 #include "modules/mediastream/RTCSessionDescriptionInit.h"
67 #include "modules/mediastream/RTCSessionDescriptionRequestImpl.h"
68 #include "modules/mediastream/RTCSessionDescriptionRequestPromiseImpl.h"
69 #include "modules/mediastream/RTCStatsCallback.h"
70 #include "modules/mediastream/RTCStatsRequestImpl.h"
71 #include "modules/mediastream/RTCVoidRequestImpl.h"
72 #include "modules/mediastream/RTCVoidRequestPromiseImpl.h"
73 #include "platform/mediastream/RTCAnswerOptionsPlatform.h"
74 #include "platform/mediastream/RTCConfiguration.h"
75 #include "platform/mediastream/RTCOfferOptionsPlatform.h"
76 #include "public/platform/Platform.h"
77 #include "public/platform/WebCryptoAlgorithmParams.h"
78 #include "public/platform/WebMediaStream.h"
79 #include "public/platform/WebRTCAnswerOptions.h"
80 #include "public/platform/WebRTCCertificate.h"
81 #include "public/platform/WebRTCCertificateGenerator.h"
82 #include "public/platform/WebRTCConfiguration.h"
83 #include "public/platform/WebRTCDataChannelHandler.h"
84 #include "public/platform/WebRTCDataChannelInit.h"
85 #include "public/platform/WebRTCICECandidate.h"
86 #include "public/platform/WebRTCKeyParams.h"
87 #include "public/platform/WebRTCOfferOptions.h"
88 #include "public/platform/WebRTCSessionDescription.h"
89 #include "public/platform/WebRTCSessionDescriptionRequest.h"
90 #include "public/platform/WebRTCStatsRequest.h"
91 #include "public/platform/WebRTCVoidRequest.h"
92 #include "wtf/CurrentTime.h"
93 #include "wtf/PtrUtil.h"
94 #include <algorithm>
95 #include <memory>
96
97 namespace blink {
98
99 namespace {
100
101 const char kSignalingStateClosedMessage[] = "The RTCPeerConnection's signalingSt ate is 'closed'.";
102
103 bool throwExceptionIfSignalingStateClosed(RTCPeerConnection::SignalingState stat e, ExceptionState& exceptionState)
104 {
105 if (state == RTCPeerConnection::SignalingStateClosed) {
106 exceptionState.throwDOMException(InvalidStateError, kSignalingStateClose dMessage);
107 return true;
108 }
109
110 return false;
111 }
112
113 void asyncCallErrorCallback(RTCPeerConnectionErrorCallback* errorCallback, DOMEx ception* exception)
114 {
115 DCHECK(errorCallback);
116 Microtask::enqueueMicrotask(bind(&RTCPeerConnectionErrorCallback::handleEven t, wrapPersistent(errorCallback), wrapPersistent(exception)));
117 }
118
119 bool callErrorCallbackIfSignalingStateClosed(RTCPeerConnection::SignalingState s tate, RTCPeerConnectionErrorCallback* errorCallback)
120 {
121 if (state == RTCPeerConnection::SignalingStateClosed) {
122 if (errorCallback)
123 asyncCallErrorCallback(errorCallback, DOMException::create(InvalidSt ateError, kSignalingStateClosedMessage));
124
125 return true;
126 }
127
128 return false;
129 }
130
131 bool isIceCandidateMissingSdp(const RTCIceCandidateInitOrRTCIceCandidate& candid ate)
132 {
133 if (candidate.isRTCIceCandidateInit()) {
134 const RTCIceCandidateInit& iceCandidateInit = candidate.getAsRTCIceCandi dateInit();
135 return !iceCandidateInit.hasSdpMid() && !iceCandidateInit.hasSdpMLineInd ex();
136 }
137
138 DCHECK(candidate.isRTCIceCandidate());
139 return false;
140 }
141
142 WebRTCOfferOptions convertToWebRTCOfferOptions(const RTCOfferOptions& options)
143 {
144 return WebRTCOfferOptions(RTCOfferOptionsPlatform::create(
145 options.hasOfferToReceiveVideo() ? std::max(options.offerToReceiveVideo( ), 0) : -1,
146 options.hasOfferToReceiveAudio() ? std::max(options.offerToReceiveAudio( ), 0) : -1,
147 options.hasVoiceActivityDetection() ? options.voiceActivityDetection() : true,
148 options.hasIceRestart() ? options.iceRestart() : false));
149 }
150
151 WebRTCAnswerOptions convertToWebRTCAnswerOptions(const RTCAnswerOptions& options )
152 {
153 return WebRTCAnswerOptions(RTCAnswerOptionsPlatform::create(
154 options.hasVoiceActivityDetection() ? options.voiceActivityDetection() : true));
155 }
156
157 WebRTCICECandidate convertToWebRTCIceCandidate(ExecutionContext* context, const RTCIceCandidateInitOrRTCIceCandidate& candidate)
158 {
159 DCHECK(!candidate.isNull());
160 if (candidate.isRTCIceCandidateInit()) {
161 const RTCIceCandidateInit& iceCandidateInit = candidate.getAsRTCIceCandi dateInit();
162 // TODO(guidou): Change default value to -1. crbug.com/614958.
163 unsigned short sdpMLineIndex = 0;
164 if (iceCandidateInit.hasSdpMLineIndex())
165 sdpMLineIndex = iceCandidateInit.sdpMLineIndex();
166 else
167 UseCounter::count(context, UseCounter::RTCIceCandidateDefaultSdpMLin eIndex);
168 return WebRTCICECandidate(iceCandidateInit.candidate(), iceCandidateInit .sdpMid(), sdpMLineIndex);
169 }
170
171 DCHECK(candidate.isRTCIceCandidate());
172 return candidate.getAsRTCIceCandidate()->webCandidate();
173 }
174
175 // Helper class for RTCPeerConnection::generateCertificate.
176 class WebRTCCertificateObserver : public WebRTCCertificateCallback {
177 public:
178 // Takes ownership of |resolver|.
179 static WebRTCCertificateObserver* create(ScriptPromiseResolver* resolver)
180 {
181 return new WebRTCCertificateObserver(resolver);
182 }
183
184 ~WebRTCCertificateObserver() override {}
185
186 private:
187 WebRTCCertificateObserver(ScriptPromiseResolver* resolver)
188 : m_resolver(resolver) {}
189
190 void onSuccess(std::unique_ptr<WebRTCCertificate> certificate) override
191 {
192 m_resolver->resolve(new RTCCertificate(std::move(certificate)));
193 }
194
195 void onError() override
196 {
197 m_resolver->reject();
198 }
199
200 Persistent<ScriptPromiseResolver> m_resolver;
201 };
202
203 RTCConfiguration* parseConfiguration(const Dictionary& configuration, ExceptionS tate& exceptionState, RtcpMuxPolicy* selectedRtcpMuxPolicy)
204 {
205 if (configuration.isUndefinedOrNull())
206 return 0;
207
208 RTCIceTransports iceTransports = RTCIceTransportsAll;
209 String iceTransportsString;
210 if (DictionaryHelper::get(configuration, "iceTransports", iceTransportsStrin g)) {
211 if (iceTransportsString == "none") {
212 iceTransports = RTCIceTransportsNone;
213 } else if (iceTransportsString == "relay") {
214 iceTransports = RTCIceTransportsRelay;
215 } else if (iceTransportsString != "all") {
216 exceptionState.throwTypeError("Malformed RTCIceTransports");
217 return 0;
218 }
219 }
220
221 ArrayValue iceServers;
222 bool ok = DictionaryHelper::get(configuration, "iceServers", iceServers);
223 if (!ok || iceServers.isUndefinedOrNull()) {
224 exceptionState.throwTypeError("Malformed RTCConfiguration");
225 return 0;
226 }
227
228 size_t numberOfServers;
229 ok = iceServers.length(numberOfServers);
230 if (!ok) {
231 exceptionState.throwTypeError("Malformed RTCConfiguration");
232 return 0;
233 }
234
235 RTCBundlePolicy bundlePolicy = RTCBundlePolicyBalanced;
236 String bundlePolicyString;
237 if (DictionaryHelper::get(configuration, "bundlePolicy", bundlePolicyString) ) {
238 if (bundlePolicyString == "max-compat") {
239 bundlePolicy = RTCBundlePolicyMaxCompat;
240 } else if (bundlePolicyString == "max-bundle") {
241 bundlePolicy = RTCBundlePolicyMaxBundle;
242 } else if (bundlePolicyString != "balanced") {
243 exceptionState.throwTypeError("Malformed RTCBundlePolicy");
244 return 0;
245 }
246 }
247
248 // For the histogram value of "WebRTC.PeerConnection.SelectedRtcpMuxPolicy".
249 *selectedRtcpMuxPolicy = RtcpMuxPolicyDefault;
250 RTCRtcpMuxPolicy rtcpMuxPolicy = RTCRtcpMuxPolicyNegotiate;
251 String rtcpMuxPolicyString;
252 if (DictionaryHelper::get(configuration, "rtcpMuxPolicy", rtcpMuxPolicyStrin g)) {
253 if (rtcpMuxPolicyString == "require") {
254 *selectedRtcpMuxPolicy = RtcpMuxPolicyRequire;
255 rtcpMuxPolicy = RTCRtcpMuxPolicyRequire;
256 } else if (rtcpMuxPolicyString == "negotiate") {
257 *selectedRtcpMuxPolicy = RtcpMuxPolicyNegotiate;
258 rtcpMuxPolicy = RTCRtcpMuxPolicyNegotiate;
259 } else {
260 exceptionState.throwTypeError("Malformed RTCRtcpMuxPolicy");
261 return 0;
262 }
263 }
264
265 RTCConfiguration* rtcConfiguration = RTCConfiguration::create();
266 rtcConfiguration->setIceTransports(iceTransports);
267 rtcConfiguration->setBundlePolicy(bundlePolicy);
268 rtcConfiguration->setRtcpMuxPolicy(rtcpMuxPolicy);
269
270 for (size_t i = 0; i < numberOfServers; ++i) {
271 Dictionary iceServer;
272 ok = iceServers.get(i, iceServer);
273 if (!ok) {
274 exceptionState.throwTypeError("Malformed RTCIceServer");
275 return 0;
276 }
277
278 Vector<String> names;
279 iceServer.getPropertyNames(names);
280
281 Vector<String> urlStrings;
282 if (names.contains("urls")) {
283 if (!DictionaryHelper::get(iceServer, "urls", urlStrings) || !urlStr ings.size()) {
284 String urlString;
285 if (DictionaryHelper::get(iceServer, "urls", urlString)) {
286 urlStrings.append(urlString);
287 } else {
288 exceptionState.throwTypeError("Malformed RTCIceServer");
289 return 0;
290 }
291 }
292 } else if (names.contains("url")) {
293 String urlString;
294 if (DictionaryHelper::get(iceServer, "url", urlString)) {
295 urlStrings.append(urlString);
296 } else {
297 exceptionState.throwTypeError("Malformed RTCIceServer");
298 return 0;
299 }
300 } else {
301 exceptionState.throwTypeError("Malformed RTCIceServer");
302 return 0;
303 }
304
305 String username, credential;
306 DictionaryHelper::get(iceServer, "username", username);
307 DictionaryHelper::get(iceServer, "credential", credential);
308
309 for (Vector<String>::iterator iter = urlStrings.begin(); iter != urlStri ngs.end(); ++iter) {
310 KURL url(KURL(), *iter);
311 if (!url.isValid() || !(url.protocolIs("turn") || url.protocolIs("tu rns") || url.protocolIs("stun"))) {
312 exceptionState.throwTypeError("Malformed URL");
313 return 0;
314 }
315
316 rtcConfiguration->appendServer(RTCIceServer::create(url, username, c redential));
317 }
318 }
319
320 ArrayValue certificates;
321 if (DictionaryHelper::get(configuration, "certificates", certificates) && !c ertificates.isUndefinedOrNull()) {
322 size_t numberOfCertificates;
323 certificates.length(numberOfCertificates);
324 for (size_t i = 0; i < numberOfCertificates; ++i) {
325 RTCCertificate* certificate = nullptr;
326
327 Dictionary dictCert;
328 certificates.get(i, dictCert);
329 v8::Local<v8::Value> valCert = dictCert.v8Value();
330 if (!valCert.IsEmpty()) {
331 certificate = V8RTCCertificate::toImplWithTypeCheck(configuratio n.isolate(), valCert);
332 }
333 if (!certificate) {
334 exceptionState.throwTypeError("Malformed sequence<RTCCertificate >");
335 return 0;
336 }
337
338 rtcConfiguration->appendCertificate(certificate->certificateShallowC opy());
339 }
340 }
341 return rtcConfiguration;
342 }
343
344 RTCOfferOptionsPlatform* parseOfferOptions(const Dictionary& options)
345 {
346 if (options.isUndefinedOrNull())
347 return 0;
348
349 Vector<String> propertyNames;
350 options.getPropertyNames(propertyNames);
351
352 // Treat |options| as MediaConstraints if it is empty or has "optional" or " mandatory" properties for compatibility.
353 // TODO(jiayl): remove constraints when RTCOfferOptions reaches Stable and c lient code is ready.
354 if (propertyNames.isEmpty() || propertyNames.contains("optional") || propert yNames.contains("mandatory"))
355 return 0;
356
357 int32_t offerToReceiveVideo = -1;
358 int32_t offerToReceiveAudio = -1;
359 bool voiceActivityDetection = true;
360 bool iceRestart = false;
361
362 if (DictionaryHelper::get(options, "offerToReceiveVideo", offerToReceiveVide o) && offerToReceiveVideo < 0)
363 offerToReceiveVideo = 0;
364 if (DictionaryHelper::get(options, "offerToReceiveAudio", offerToReceiveAudi o) && offerToReceiveAudio < 0)
365 offerToReceiveAudio = 0;
366 DictionaryHelper::get(options, "voiceActivityDetection", voiceActivityDetect ion);
367 DictionaryHelper::get(options, "iceRestart", iceRestart);
368
369 RTCOfferOptionsPlatform* rtcOfferOptions = RTCOfferOptionsPlatform::create(o fferToReceiveVideo, offerToReceiveAudio, voiceActivityDetection, iceRestart);
370 return rtcOfferOptions;
371 }
372
373 } // namespace
374
375 RTCPeerConnection::EventWrapper::EventWrapper(
376 Event* event,
377 std::unique_ptr<BoolFunction> function)
378 : m_event(event)
379 , m_setupFunction(std::move(function))
380 {
381 }
382
383 bool RTCPeerConnection::EventWrapper::setup()
384 {
385 if (m_setupFunction) {
386 return (*m_setupFunction)();
387 }
388 return true;
389 }
390
391 DEFINE_TRACE(RTCPeerConnection::EventWrapper)
392 {
393 visitor->trace(m_event);
394 }
395
396 RTCPeerConnection* RTCPeerConnection::create(ExecutionContext* context, const Di ctionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
397 {
398 if (mediaConstraints.isObject())
399 UseCounter::count(context, UseCounter::RTCPeerConnectionConstructorConst raints);
400 else
401 UseCounter::count(context, UseCounter::RTCPeerConnectionConstructorCompl iant);
402
403 // Record the RtcpMuxPolicy for histogram "WebRTC.PeerConnection.SelectedRtc pMuxPolicy".
404 RtcpMuxPolicy selectedRtcpMuxPolicy = RtcpMuxPolicyDefault;
405 RTCConfiguration* configuration = parseConfiguration(rtcConfiguration, excep tionState, &selectedRtcpMuxPolicy);
406 if (exceptionState.hadException())
407 return 0;
408
409 // Make sure no certificates have expired.
410 if (configuration && configuration->numberOfCertificates() > 0) {
411 DOMTimeStamp now = convertSecondsToDOMTimeStamp(currentTime());
412 for (size_t i = 0; i < configuration->numberOfCertificates(); ++i) {
413 DOMTimeStamp expires = configuration->certificate(i)->expires();
414 if (expires <= now) {
415 exceptionState.throwDOMException(InvalidStateError, "Expired cer tificate(s).");
416 return 0;
417 }
418 }
419 }
420
421 MediaErrorState mediaErrorState;
422 WebMediaConstraints constraints = MediaConstraintsImpl::create(context, medi aConstraints, mediaErrorState);
423 if (mediaErrorState.hadException()) {
424 mediaErrorState.raiseException(exceptionState);
425 return 0;
426 }
427
428 RTCPeerConnection* peerConnection = new RTCPeerConnection(context, configura tion, constraints, exceptionState);
429 peerConnection->suspendIfNeeded();
430 if (exceptionState.hadException())
431 return 0;
432
433 peerConnection->m_peerHandler->logSelectedRtcpMuxPolicy(selectedRtcpMuxPolic y);
434
435 return peerConnection;
436 }
437
438 RTCPeerConnection::RTCPeerConnection(ExecutionContext* context, RTCConfiguration * configuration, WebMediaConstraints constraints, ExceptionState& exceptionState )
439 : ActiveScriptWrappable(this)
440 , ActiveDOMObject(context)
441 , m_signalingState(SignalingStateStable)
442 , m_iceGatheringState(ICEGatheringStateNew)
443 , m_iceConnectionState(ICEConnectionStateNew)
444 , m_dispatchScheduledEventRunner(AsyncMethodRunner<RTCPeerConnection>::creat e(this, &RTCPeerConnection::dispatchScheduledEvent))
445 , m_stopped(false)
446 , m_closed(false)
447 {
448 ThreadState::current()->registerPreFinalizer(this);
449 Document* document = toDocument(getExecutionContext());
450
451 // If we fail, set |m_closed| and |m_stopped| to true, to avoid hitting the assert in the destructor.
452
453 if (!document->frame()) {
454 m_closed = true;
455 m_stopped = true;
456 exceptionState.throwDOMException(NotSupportedError, "PeerConnections may not be created in detached documents.");
457 return;
458 }
459
460 m_peerHandler = wrapUnique(Platform::current()->createRTCPeerConnectionHandl er(this));
461 if (!m_peerHandler) {
462 m_closed = true;
463 m_stopped = true;
464 exceptionState.throwDOMException(NotSupportedError, "No PeerConnection h andler can be created, perhaps WebRTC is disabled?");
465 return;
466 }
467
468 document->frame()->loader().client()->dispatchWillStartUsingPeerConnectionHa ndler(m_peerHandler.get());
469
470 if (!m_peerHandler->initialize(configuration, constraints)) {
471 m_closed = true;
472 m_stopped = true;
473 exceptionState.throwDOMException(NotSupportedError, "Failed to initializ e native PeerConnection.");
474 return;
475 }
476 }
477
478 RTCPeerConnection::~RTCPeerConnection()
479 {
480 // This checks that close() or stop() is called before the destructor.
481 // We are assuming that a wrapper is always created when RTCPeerConnection i s created.
482 DCHECK(m_closed || m_stopped);
483 }
484
485 void RTCPeerConnection::dispose()
486 {
487 // Promptly clears a raw reference from content/ to an on-heap object
488 // so that content/ doesn't access it in a lazy sweeping phase.
489 m_peerHandler.reset();
490 }
491
492 ScriptPromise RTCPeerConnection::createOffer(ScriptState* scriptState, const RTC OfferOptions& options)
493 {
494 if (m_signalingState == SignalingStateClosed)
495 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, kSignalingStateClosedMessage));
496
497 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
498 ScriptPromise promise = resolver->promise();
499 RTCSessionDescriptionRequest* request = RTCSessionDescriptionRequestPromiseI mpl::create(this, resolver);
500 m_peerHandler->createOffer(request, convertToWebRTCOfferOptions(options));
501 return promise;
502 }
503
504 ScriptPromise RTCPeerConnection::createOffer(ScriptState* scriptState, RTCSessio nDescriptionCallback* successCallback, RTCPeerConnectionErrorCallback* errorCall back, const Dictionary& rtcOfferOptions)
505 {
506 DCHECK(successCallback);
507 DCHECK(errorCallback);
508 ExecutionContext* context = scriptState->getExecutionContext();
509 UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferLegacyFai lureCallback);
510 if (callErrorCallbackIfSignalingStateClosed(m_signalingState, errorCallback) )
511 return ScriptPromise::castUndefined(scriptState);
512
513 RTCOfferOptionsPlatform* offerOptions = parseOfferOptions(rtcOfferOptions);
514 RTCSessionDescriptionRequest* request = RTCSessionDescriptionRequestImpl::cr eate(getExecutionContext(), this, successCallback, errorCallback);
515
516 if (offerOptions) {
517 if (offerOptions->offerToReceiveAudio() != -1 || offerOptions->offerToRe ceiveVideo() != -1)
518 UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferL egacyOfferOptions);
519 else
520 UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferL egacyCompliant);
521
522 m_peerHandler->createOffer(request, WebRTCOfferOptions(offerOptions));
523 } else {
524 MediaErrorState mediaErrorState;
525 WebMediaConstraints constraints = MediaConstraintsImpl::create(context, rtcOfferOptions, mediaErrorState);
526 // Report constraints parsing errors via the callback, but ignore unknow n/unsupported constraints as they
527 // would be silently discarded by WebIDL.
528 if (mediaErrorState.canGenerateException()) {
529 String errorMsg = mediaErrorState.getErrorMessage();
530 asyncCallErrorCallback(errorCallback, DOMException::create(Operation Error, errorMsg));
531 return ScriptPromise::castUndefined(scriptState);
532 }
533
534 if (!constraints.isEmpty())
535 UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferL egacyConstraints);
536 else
537 UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferL egacyCompliant);
538
539 m_peerHandler->createOffer(request, constraints);
540 }
541
542 return ScriptPromise::castUndefined(scriptState);
543 }
544
545 ScriptPromise RTCPeerConnection::createAnswer(ScriptState* scriptState, const RT CAnswerOptions& options)
546 {
547 if (m_signalingState == SignalingStateClosed)
548 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, kSignalingStateClosedMessage));
549
550 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
551 ScriptPromise promise = resolver->promise();
552 RTCSessionDescriptionRequest* request = RTCSessionDescriptionRequestPromiseI mpl::create(this, resolver);
553 m_peerHandler->createAnswer(request, convertToWebRTCAnswerOptions(options));
554 return promise;
555 }
556
557 ScriptPromise RTCPeerConnection::createAnswer(ScriptState* scriptState, RTCSessi onDescriptionCallback* successCallback, RTCPeerConnectionErrorCallback* errorCal lback, const Dictionary& mediaConstraints)
558 {
559 DCHECK(successCallback);
560 DCHECK(errorCallback);
561 ExecutionContext* context = scriptState->getExecutionContext();
562 UseCounter::count(context, UseCounter::RTCPeerConnectionCreateAnswerLegacyFa ilureCallback);
563 if (mediaConstraints.isObject())
564 UseCounter::count(context, UseCounter::RTCPeerConnectionCreateAnswerLega cyConstraints);
565 else
566 UseCounter::count(context, UseCounter::RTCPeerConnectionCreateAnswerLega cyCompliant);
567
568 if (callErrorCallbackIfSignalingStateClosed(m_signalingState, errorCallback) )
569 return ScriptPromise::castUndefined(scriptState);
570
571 MediaErrorState mediaErrorState;
572 WebMediaConstraints constraints = MediaConstraintsImpl::create(context, medi aConstraints, mediaErrorState);
573 // Report constraints parsing errors via the callback, but ignore unknown/un supported constraints as they
574 // would be silently discarded by WebIDL.
575 if (mediaErrorState.canGenerateException()) {
576 String errorMsg = mediaErrorState.getErrorMessage();
577 asyncCallErrorCallback(errorCallback, DOMException::create(OperationErro r, errorMsg));
578 return ScriptPromise::castUndefined(scriptState);
579 }
580
581 RTCSessionDescriptionRequest* request = RTCSessionDescriptionRequestImpl::cr eate(getExecutionContext(), this, successCallback, errorCallback);
582 m_peerHandler->createAnswer(request, constraints);
583 return ScriptPromise::castUndefined(scriptState);
584 }
585
586 ScriptPromise RTCPeerConnection::setLocalDescription(ScriptState* scriptState, c onst RTCSessionDescriptionInit& sessionDescriptionInit)
587 {
588 if (m_signalingState == SignalingStateClosed)
589 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, kSignalingStateClosedMessage));
590
591 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
592 ScriptPromise promise = resolver->promise();
593 RTCVoidRequest* request = RTCVoidRequestPromiseImpl::create(this, resolver);
594 m_peerHandler->setLocalDescription(request, WebRTCSessionDescription(session DescriptionInit.type(), sessionDescriptionInit.sdp()));
595 return promise;
596 }
597
598 ScriptPromise RTCPeerConnection::setLocalDescription(ScriptState* scriptState, c onst RTCSessionDescriptionInit& sessionDescriptionInit, VoidCallback* successCal lback, RTCPeerConnectionErrorCallback* errorCallback)
599 {
600 ExecutionContext* context = scriptState->getExecutionContext();
601 if (successCallback && errorCallback) {
602 UseCounter::count(context, UseCounter::RTCPeerConnectionSetLocalDescript ionLegacyCompliant);
603 } else {
604 if (!successCallback)
605 UseCounter::count(context, UseCounter::RTCPeerConnectionSetLocalDesc riptionLegacyNoSuccessCallback);
606 if (!errorCallback)
607 UseCounter::count(context, UseCounter::RTCPeerConnectionSetLocalDesc riptionLegacyNoFailureCallback);
608 }
609
610 if (callErrorCallbackIfSignalingStateClosed(m_signalingState, errorCallback) )
611 return ScriptPromise::castUndefined(scriptState);
612
613 RTCVoidRequest* request = RTCVoidRequestImpl::create(getExecutionContext(), this, successCallback, errorCallback);
614 m_peerHandler->setLocalDescription(request, WebRTCSessionDescription(session DescriptionInit.type(), sessionDescriptionInit.sdp()));
615 return ScriptPromise::castUndefined(scriptState);
616 }
617
618 RTCSessionDescription* RTCPeerConnection::localDescription()
619 {
620 WebRTCSessionDescription webSessionDescription = m_peerHandler->localDescrip tion();
621 if (webSessionDescription.isNull())
622 return nullptr;
623
624 return RTCSessionDescription::create(webSessionDescription);
625 }
626
627 ScriptPromise RTCPeerConnection::setRemoteDescription(ScriptState* scriptState, const RTCSessionDescriptionInit& sessionDescriptionInit)
628 {
629 if (m_signalingState == SignalingStateClosed)
630 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, kSignalingStateClosedMessage));
631
632 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
633 ScriptPromise promise = resolver->promise();
634 RTCVoidRequest* request = RTCVoidRequestPromiseImpl::create(this, resolver);
635 m_peerHandler->setRemoteDescription(request, WebRTCSessionDescription(sessio nDescriptionInit.type(), sessionDescriptionInit.sdp()));
636 return promise;
637 }
638
639 ScriptPromise RTCPeerConnection::setRemoteDescription(ScriptState* scriptState, const RTCSessionDescriptionInit& sessionDescriptionInit, VoidCallback* successCa llback, RTCPeerConnectionErrorCallback* errorCallback)
640 {
641 ExecutionContext* context = scriptState->getExecutionContext();
642 if (successCallback && errorCallback) {
643 UseCounter::count(context, UseCounter::RTCPeerConnectionSetRemoteDescrip tionLegacyCompliant);
644 } else {
645 if (!successCallback)
646 UseCounter::count(context, UseCounter::RTCPeerConnectionSetRemoteDes criptionLegacyNoSuccessCallback);
647 if (!errorCallback)
648 UseCounter::count(context, UseCounter::RTCPeerConnectionSetRemoteDes criptionLegacyNoFailureCallback);
649 }
650
651 if (callErrorCallbackIfSignalingStateClosed(m_signalingState, errorCallback) )
652 return ScriptPromise::castUndefined(scriptState);
653
654 RTCVoidRequest* request = RTCVoidRequestImpl::create(getExecutionContext(), this, successCallback, errorCallback);
655 m_peerHandler->setRemoteDescription(request, WebRTCSessionDescription(sessio nDescriptionInit.type(), sessionDescriptionInit.sdp()));
656 return ScriptPromise::castUndefined(scriptState);
657 }
658
659 RTCSessionDescription* RTCPeerConnection::remoteDescription()
660 {
661 WebRTCSessionDescription webSessionDescription = m_peerHandler->remoteDescri ption();
662 if (webSessionDescription.isNull())
663 return nullptr;
664
665 return RTCSessionDescription::create(webSessionDescription);
666 }
667
668 void RTCPeerConnection::updateIce(ExecutionContext* context, const Dictionary& r tcConfiguration, const Dictionary& mediaConstraints, ExceptionState& exceptionSt ate)
669 {
670 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
671 return;
672
673 RtcpMuxPolicy selectedRtcpMuxPolicy = RtcpMuxPolicyDefault;
674 RTCConfiguration* configuration = parseConfiguration(rtcConfiguration, excep tionState, &selectedRtcpMuxPolicy);
675
676 if (exceptionState.hadException())
677 return;
678
679 MediaErrorState mediaErrorState;
680 if (mediaErrorState.hadException()) {
681 mediaErrorState.raiseException(exceptionState);
682 return;
683 }
684
685 // Constraints are ignored.
686 bool valid = m_peerHandler->updateICE(configuration);
687 if (!valid)
688 exceptionState.throwDOMException(SyntaxError, "Could not update the ICE Agent with the given configuration.");
689 }
690
691 ScriptPromise RTCPeerConnection::generateCertificate(ScriptState* scriptState, c onst AlgorithmIdentifier& keygenAlgorithm, ExceptionState& exceptionState)
692 {
693 // Normalize |keygenAlgorithm| with WebCrypto, making sure it is a recognize d AlgorithmIdentifier.
694 WebCryptoAlgorithm cryptoAlgorithm;
695 AlgorithmError error;
696 if (!normalizeAlgorithm(keygenAlgorithm, WebCryptoOperationGenerateKey, cryp toAlgorithm, &error)) {
697 // Reject generateCertificate with the same error as was produced by Web Crypto.
698 // |result| is garbage collected, no need to delete.
699 CryptoResultImpl* result = CryptoResultImpl::create(scriptState);
700 ScriptPromise promise = result->promise();
701 result->completeWithError(error.errorType, error.errorDetails);
702 return promise;
703 }
704
705 // Check if |keygenAlgorithm| contains the optional DOMTimeStamp |expires| a ttribute.
706 Nullable<DOMTimeStamp> expires;
707 if (keygenAlgorithm.isDictionary()) {
708 Dictionary keygenAlgorithmDict = keygenAlgorithm.getAsDictionary();
709 if (keygenAlgorithmDict.hasProperty("expires")) {
710 v8::Local<v8::Value> expiresValue;
711 keygenAlgorithmDict.get("expires", expiresValue);
712 if (expiresValue->IsNumber()) {
713 double expiresDouble = expiresValue->ToNumber(scriptState->isola te()->GetCurrentContext()).ToLocalChecked()->Value();
714 if (expiresDouble >= 0) {
715 expires.set(static_cast<DOMTimeStamp>(expiresDouble));
716 }
717 }
718 }
719 }
720
721 // Convert from WebCrypto representation to recognized WebRTCKeyParams. WebR TC supports a small subset of what are valid AlgorithmIdentifiers.
722 const char* unsupportedParamsString = "The 1st argument provided is an Algor ithmIdentifier with a supported algorithm name, but the parameters are not suppo rted.";
723 Nullable<WebRTCKeyParams> keyParams;
724 switch (cryptoAlgorithm.id()) {
725 case WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
726 // name: "RSASSA-PKCS1-v1_5"
727 unsigned publicExponent;
728 // "publicExponent" must fit in an unsigned int. The only recognized "ha sh" is "SHA-256".
729 if (cryptoAlgorithm.rsaHashedKeyGenParams()->convertPublicExponentToUnsi gned(publicExponent)
730 && cryptoAlgorithm.rsaHashedKeyGenParams()->hash().id() == WebCrypto AlgorithmIdSha256) {
731 unsigned modulusLength = cryptoAlgorithm.rsaHashedKeyGenParams()->mo dulusLengthBits();
732 keyParams.set(WebRTCKeyParams::createRSA(modulusLength, publicExpone nt));
733 } else {
734 return ScriptPromise::rejectWithDOMException(scriptState, DOMExcepti on::create(NotSupportedError, unsupportedParamsString));
735 }
736 break;
737 case WebCryptoAlgorithmIdEcdsa:
738 // name: "ECDSA"
739 // The only recognized "namedCurve" is "P-256".
740 if (cryptoAlgorithm.ecKeyGenParams()->namedCurve() == WebCryptoNamedCurv eP256) {
741 keyParams.set(WebRTCKeyParams::createECDSA(WebRTCECCurveNistP256));
742 } else {
743 return ScriptPromise::rejectWithDOMException(scriptState, DOMExcepti on::create(NotSupportedError, unsupportedParamsString));
744 }
745 break;
746 default:
747 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(NotSupportedError, "The 1st argument provided is an AlgorithmIdentifier, but the algorithm is not supported."));
748 break;
749 }
750 DCHECK(!keyParams.isNull());
751
752 std::unique_ptr<WebRTCCertificateGenerator> certificateGenerator = wrapUniqu e(
753 Platform::current()->createRTCCertificateGenerator());
754
755 // |keyParams| was successfully constructed, but does the certificate genera tor support these parameters?
756 if (!certificateGenerator->isSupportedKeyParams(keyParams.get())) {
757 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(NotSupportedError, unsupportedParamsString));
758 }
759
760 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
761 ScriptPromise promise = resolver->promise();
762
763 std::unique_ptr<WebRTCCertificateObserver> certificateObserver(WebRTCCertifi cateObserver::create(resolver));
764
765 // Generate certificate. The |certificateObserver| will resolve the promise asynchronously upon completion.
766 // The observer will manage its own destruction as well as the resolver's de struction.
767 if (expires.isNull()) {
768 certificateGenerator->generateCertificate(
769 keyParams.get(),
770 std::move(certificateObserver));
771 } else {
772 certificateGenerator->generateCertificateWithExpiration(
773 keyParams.get(),
774 expires.get(),
775 std::move(certificateObserver));
776 }
777
778 return promise;
779 }
780
781 ScriptPromise RTCPeerConnection::addIceCandidate(ScriptState* scriptState, const RTCIceCandidateInitOrRTCIceCandidate& candidate)
782 {
783 if (m_signalingState == SignalingStateClosed)
784 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, kSignalingStateClosedMessage));
785
786 if (isIceCandidateMissingSdp(candidate))
787 return ScriptPromise::reject(scriptState, V8ThrowException::createTypeEr ror(scriptState->isolate(), "Candidate missing values for both sdpMid and sdpMLi neIndex"));
788
789 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
790 ScriptPromise promise = resolver->promise();
791 RTCVoidRequest* request = RTCVoidRequestPromiseImpl::create(this, resolver);
792 WebRTCICECandidate webCandidate = convertToWebRTCIceCandidate(scriptState->g etExecutionContext(), candidate);
793 bool implemented = m_peerHandler->addICECandidate(request, webCandidate);
794 if (!implemented)
795 resolver->reject(DOMException::create(OperationError, "This operation co uld not be completed."));
796
797 return promise;
798 }
799
800 ScriptPromise RTCPeerConnection::addIceCandidate(ScriptState* scriptState, const RTCIceCandidateInitOrRTCIceCandidate& candidate, VoidCallback* successCallback, RTCPeerConnectionErrorCallback* errorCallback)
801 {
802 DCHECK(successCallback);
803 DCHECK(errorCallback);
804
805 if (callErrorCallbackIfSignalingStateClosed(m_signalingState, errorCallback) )
806 return ScriptPromise::castUndefined(scriptState);
807
808 if (isIceCandidateMissingSdp(candidate))
809 return ScriptPromise::reject(scriptState, V8ThrowException::createTypeEr ror(scriptState->isolate(), "Candidate missing values for both sdpMid and sdpMLi neIndex"));
810
811 RTCVoidRequest* request = RTCVoidRequestImpl::create(getExecutionContext(), this, successCallback, errorCallback);
812 WebRTCICECandidate webCandidate = convertToWebRTCIceCandidate(scriptState->g etExecutionContext(), candidate);
813 bool implemented = m_peerHandler->addICECandidate(request, webCandidate);
814 if (!implemented)
815 asyncCallErrorCallback(errorCallback, DOMException::create(OperationErro r, "This operation could not be completed."));
816
817 return ScriptPromise::castUndefined(scriptState);
818 }
819
820 String RTCPeerConnection::signalingState() const
821 {
822 switch (m_signalingState) {
823 case SignalingStateStable:
824 return "stable";
825 case SignalingStateHaveLocalOffer:
826 return "have-local-offer";
827 case SignalingStateHaveRemoteOffer:
828 return "have-remote-offer";
829 case SignalingStateHaveLocalPrAnswer:
830 return "have-local-pranswer";
831 case SignalingStateHaveRemotePrAnswer:
832 return "have-remote-pranswer";
833 case SignalingStateClosed:
834 return "closed";
835 }
836
837 NOTREACHED();
838 return String();
839 }
840
841 String RTCPeerConnection::iceGatheringState() const
842 {
843 switch (m_iceGatheringState) {
844 case ICEGatheringStateNew:
845 return "new";
846 case ICEGatheringStateGathering:
847 return "gathering";
848 case ICEGatheringStateComplete:
849 return "complete";
850 }
851
852 NOTREACHED();
853 return String();
854 }
855
856 String RTCPeerConnection::iceConnectionState() const
857 {
858 switch (m_iceConnectionState) {
859 case ICEConnectionStateNew:
860 return "new";
861 case ICEConnectionStateChecking:
862 return "checking";
863 case ICEConnectionStateConnected:
864 return "connected";
865 case ICEConnectionStateCompleted:
866 return "completed";
867 case ICEConnectionStateFailed:
868 return "failed";
869 case ICEConnectionStateDisconnected:
870 return "disconnected";
871 case ICEConnectionStateClosed:
872 return "closed";
873 }
874
875 NOTREACHED();
876 return String();
877 }
878
879 void RTCPeerConnection::addStream(ExecutionContext* context, MediaStream* stream , const Dictionary& mediaConstraints, ExceptionState& exceptionState)
880 {
881 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
882 return;
883
884 if (!stream) {
885 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "MediaStream"));
886 return;
887 }
888
889 if (m_localStreams.contains(stream))
890 return;
891
892 MediaErrorState mediaErrorState;
893 WebMediaConstraints constraints = MediaConstraintsImpl::create(context, medi aConstraints, mediaErrorState);
894 if (mediaErrorState.hadException()) {
895 mediaErrorState.raiseException(exceptionState);
896 return;
897 }
898
899 m_localStreams.append(stream);
900
901 bool valid = m_peerHandler->addStream(stream->descriptor(), constraints);
902 if (!valid)
903 exceptionState.throwDOMException(SyntaxError, "Unable to add the provide d stream.");
904 }
905
906 void RTCPeerConnection::removeStream(MediaStream* stream, ExceptionState& except ionState)
907 {
908 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
909 return;
910
911 if (!stream) {
912 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "MediaStream"));
913 return;
914 }
915
916 size_t pos = m_localStreams.find(stream);
917 if (pos == kNotFound)
918 return;
919
920 m_localStreams.remove(pos);
921
922 m_peerHandler->removeStream(stream->descriptor());
923 }
924
925 MediaStreamVector RTCPeerConnection::getLocalStreams() const
926 {
927 return m_localStreams;
928 }
929
930 MediaStreamVector RTCPeerConnection::getRemoteStreams() const
931 {
932 return m_remoteStreams;
933 }
934
935 MediaStream* RTCPeerConnection::getStreamById(const String& streamId)
936 {
937 for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_lo calStreams.end(); ++iter) {
938 if ((*iter)->id() == streamId)
939 return iter->get();
940 }
941
942 for (MediaStreamVector::iterator iter = m_remoteStreams.begin(); iter != m_r emoteStreams.end(); ++iter) {
943 if ((*iter)->id() == streamId)
944 return iter->get();
945 }
946
947 return 0;
948 }
949
950 void RTCPeerConnection::getStats(ExecutionContext* context, RTCStatsCallback* su ccessCallback, MediaStreamTrack* selector)
951 {
952 UseCounter::count(context, UseCounter::RTCPeerConnectionGetStatsLegacyNonCom pliant);
953 RTCStatsRequest* statsRequest = RTCStatsRequestImpl::create(getExecutionCont ext(), this, successCallback, selector);
954 // FIXME: Add passing selector as part of the statsRequest.
955 m_peerHandler->getStats(statsRequest);
956 }
957
958 RTCDataChannel* RTCPeerConnection::createDataChannel(String label, const Diction ary& options, ExceptionState& exceptionState)
959 {
960 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
961 return nullptr;
962
963 WebRTCDataChannelInit init;
964 DictionaryHelper::get(options, "ordered", init.ordered);
965 DictionaryHelper::get(options, "negotiated", init.negotiated);
966
967 unsigned short value = 0;
968 if (DictionaryHelper::get(options, "id", value))
969 init.id = value;
970 if (DictionaryHelper::get(options, "maxRetransmits", value))
971 init.maxRetransmits = value;
972 if (DictionaryHelper::get(options, "maxRetransmitTime", value))
973 init.maxRetransmitTime = value;
974
975 String protocolString;
976 DictionaryHelper::get(options, "protocol", protocolString);
977 init.protocol = protocolString;
978
979 RTCDataChannel* channel = RTCDataChannel::create(getExecutionContext(), m_pe erHandler.get(), label, init, exceptionState);
980 if (exceptionState.hadException())
981 return nullptr;
982 RTCDataChannel::ReadyState handlerState = channel->getHandlerState();
983 if (handlerState != RTCDataChannel::ReadyStateConnecting) {
984 // There was an early state transition. Don't miss it!
985 channel->didChangeReadyState(handlerState);
986 }
987 return channel;
988 }
989
990 bool RTCPeerConnection::hasLocalStreamWithTrackId(const String& trackId)
991 {
992 for (MediaStreamVector::iterator iter = m_localStreams.begin(); iter != m_lo calStreams.end(); ++iter) {
993 if ((*iter)->getTrackById(trackId))
994 return true;
995 }
996 return false;
997 }
998
999 RTCDTMFSender* RTCPeerConnection::createDTMFSender(MediaStreamTrack* track, Exce ptionState& exceptionState)
1000 {
1001 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
1002 return nullptr;
1003
1004 DCHECK(track);
1005
1006 if (!hasLocalStreamWithTrackId(track->id())) {
1007 exceptionState.throwDOMException(SyntaxError, "No local stream is availa ble for the track provided.");
1008 return nullptr;
1009 }
1010
1011 RTCDTMFSender* dtmfSender = RTCDTMFSender::create(getExecutionContext(), m_p eerHandler.get(), track, exceptionState);
1012 if (exceptionState.hadException())
1013 return nullptr;
1014 return dtmfSender;
1015 }
1016
1017 void RTCPeerConnection::close(ExceptionState& exceptionState)
1018 {
1019 if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
1020 return;
1021
1022 closeInternal();
1023 }
1024
1025 void RTCPeerConnection::negotiationNeeded()
1026 {
1027 DCHECK(!m_closed);
1028 scheduleDispatchEvent(Event::create(EventTypeNames::negotiationneeded));
1029 }
1030
1031 void RTCPeerConnection::didGenerateICECandidate(const WebRTCICECandidate& webCan didate)
1032 {
1033 DCHECK(!m_closed);
1034 DCHECK(getExecutionContext()->isContextThread());
1035 if (webCandidate.isNull())
1036 scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, nullptr ));
1037 else {
1038 RTCIceCandidate* iceCandidate = RTCIceCandidate::create(webCandidate);
1039 scheduleDispatchEvent(RTCIceCandidateEvent::create(false, false, iceCand idate));
1040 }
1041 }
1042
1043 void RTCPeerConnection::didChangeSignalingState(SignalingState newState)
1044 {
1045 DCHECK(!m_closed);
1046 DCHECK(getExecutionContext()->isContextThread());
1047 changeSignalingState(newState);
1048 }
1049
1050 void RTCPeerConnection::didChangeICEGatheringState(ICEGatheringState newState)
1051 {
1052 DCHECK(!m_closed);
1053 DCHECK(getExecutionContext()->isContextThread());
1054 changeIceGatheringState(newState);
1055 }
1056
1057 void RTCPeerConnection::didChangeICEConnectionState(ICEConnectionState newState)
1058 {
1059 DCHECK(!m_closed);
1060 DCHECK(getExecutionContext()->isContextThread());
1061 changeIceConnectionState(newState);
1062 }
1063
1064 void RTCPeerConnection::didAddRemoteStream(const WebMediaStream& remoteStream)
1065 {
1066 DCHECK(!m_closed);
1067 DCHECK(getExecutionContext()->isContextThread());
1068
1069 if (m_signalingState == SignalingStateClosed)
1070 return;
1071
1072 MediaStream* stream = MediaStream::create(getExecutionContext(), remoteStrea m);
1073 m_remoteStreams.append(stream);
1074
1075 scheduleDispatchEvent(MediaStreamEvent::create(EventTypeNames::addstream, fa lse, false, stream));
1076 }
1077
1078 void RTCPeerConnection::didRemoveRemoteStream(const WebMediaStream& remoteStream )
1079 {
1080 DCHECK(!m_closed);
1081 DCHECK(getExecutionContext()->isContextThread());
1082
1083 MediaStreamDescriptor* streamDescriptor = remoteStream;
1084 DCHECK(streamDescriptor->client());
1085
1086 MediaStream* stream = static_cast<MediaStream*>(streamDescriptor->client());
1087 stream->streamEnded();
1088
1089 if (m_signalingState == SignalingStateClosed)
1090 return;
1091
1092 size_t pos = m_remoteStreams.find(stream);
1093 DCHECK(pos != kNotFound);
1094 m_remoteStreams.remove(pos);
1095
1096 scheduleDispatchEvent(MediaStreamEvent::create(EventTypeNames::removestream, false, false, stream));
1097 }
1098
1099 void RTCPeerConnection::didAddRemoteDataChannel(WebRTCDataChannelHandler* handle r)
1100 {
1101 DCHECK(!m_closed);
1102 DCHECK(getExecutionContext()->isContextThread());
1103
1104 if (m_signalingState == SignalingStateClosed)
1105 return;
1106
1107 RTCDataChannel* channel = RTCDataChannel::create(getExecutionContext(), wrap Unique(handler));
1108 scheduleDispatchEvent(RTCDataChannelEvent::create(EventTypeNames::datachanne l, false, false, channel));
1109 }
1110
1111 void RTCPeerConnection::releasePeerConnectionHandler()
1112 {
1113 stop();
1114 }
1115
1116 void RTCPeerConnection::closePeerConnection()
1117 {
1118 DCHECK(m_signalingState != RTCPeerConnection::SignalingStateClosed);
1119 closeInternal();
1120 }
1121
1122 const AtomicString& RTCPeerConnection::interfaceName() const
1123 {
1124 return EventTargetNames::RTCPeerConnection;
1125 }
1126
1127 ExecutionContext* RTCPeerConnection::getExecutionContext() const
1128 {
1129 return ActiveDOMObject::getExecutionContext();
1130 }
1131
1132 void RTCPeerConnection::suspend()
1133 {
1134 m_dispatchScheduledEventRunner->suspend();
1135 }
1136
1137 void RTCPeerConnection::resume()
1138 {
1139 m_dispatchScheduledEventRunner->resume();
1140 }
1141
1142 void RTCPeerConnection::stop()
1143 {
1144 if (m_stopped)
1145 return;
1146
1147 m_stopped = true;
1148 m_iceConnectionState = ICEConnectionStateClosed;
1149 m_signalingState = SignalingStateClosed;
1150
1151 m_dispatchScheduledEventRunner->stop();
1152
1153 m_peerHandler.reset();
1154 }
1155
1156 void RTCPeerConnection::changeSignalingState(SignalingState signalingState)
1157 {
1158 if (m_signalingState != SignalingStateClosed && m_signalingState != signalin gState) {
1159 m_signalingState = signalingState;
1160 scheduleDispatchEvent(Event::create(EventTypeNames::signalingstatechange ));
1161 }
1162 }
1163
1164 void RTCPeerConnection::changeIceGatheringState(ICEGatheringState iceGatheringSt ate)
1165 {
1166 m_iceGatheringState = iceGatheringState;
1167 }
1168
1169 bool RTCPeerConnection::setIceConnectionState(ICEConnectionState iceConnectionSt ate)
1170 {
1171 if (m_iceConnectionState != ICEConnectionStateClosed && m_iceConnectionState != iceConnectionState) {
1172 m_iceConnectionState = iceConnectionState;
1173 return true;
1174 }
1175 return false;
1176 }
1177
1178 void RTCPeerConnection::changeIceConnectionState(ICEConnectionState iceConnectio nState)
1179 {
1180 if (m_iceConnectionState != ICEConnectionStateClosed) {
1181 scheduleDispatchEvent(Event::create(EventTypeNames::iceconnectionstatech ange),
1182 WTF::bind(&RTCPeerConnection::setIceConnectionState, wrapPersistent( this), iceConnectionState));
1183 }
1184 }
1185
1186 void RTCPeerConnection::closeInternal()
1187 {
1188 DCHECK(m_signalingState != RTCPeerConnection::SignalingStateClosed);
1189 m_peerHandler->stop();
1190 m_closed = true;
1191
1192 changeIceConnectionState(ICEConnectionStateClosed);
1193 changeIceGatheringState(ICEGatheringStateComplete);
1194 changeSignalingState(SignalingStateClosed);
1195 }
1196
1197 void RTCPeerConnection::scheduleDispatchEvent(Event* event)
1198 {
1199 scheduleDispatchEvent(event, nullptr);
1200 }
1201
1202 void RTCPeerConnection::scheduleDispatchEvent(Event* event,
1203 std::unique_ptr<BoolFunction> setupFunction)
1204 {
1205 m_scheduledEvents.append(new EventWrapper(event, std::move(setupFunction)));
1206
1207 m_dispatchScheduledEventRunner->runAsync();
1208 }
1209
1210 void RTCPeerConnection::dispatchScheduledEvent()
1211 {
1212 if (m_stopped)
1213 return;
1214
1215 HeapVector<Member<EventWrapper>> events;
1216 events.swap(m_scheduledEvents);
1217
1218 HeapVector<Member<EventWrapper>>::iterator it = events.begin();
1219 for (; it != events.end(); ++it) {
1220 if ((*it)->setup()) {
1221 dispatchEvent((*it)->m_event.release());
1222 }
1223 }
1224
1225 events.clear();
1226 }
1227
1228 DEFINE_TRACE(RTCPeerConnection)
1229 {
1230 visitor->trace(m_localStreams);
1231 visitor->trace(m_remoteStreams);
1232 visitor->trace(m_dispatchScheduledEventRunner);
1233 visitor->trace(m_scheduledEvents);
1234 EventTargetWithInlineData::trace(visitor);
1235 ActiveDOMObject::trace(visitor);
1236 }
1237
1238 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698