<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[208445] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/208445">208445</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-11-09 10:28:08 -0800 (Wed, 09 Nov 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[WebRTC] Introduce asynchronous backend for other RTCPeerConnection API
https://bugs.webkit.org/show_bug.cgi?id=164409

Patch by Youenn Fablet &lt;youenn@apple.com&gt; on 2016-11-09
Reviewed by Eric Carlson.

Source/WebCore:

Covered by existing tests.

Following on createOffer changes, applying the same changes to createAnswer, setLocalDescription, setRemoteDescription and addIceCandidate.
Also refactored ICE candidate event generation (done at PeerConnectionBackend).
Updated stop implementation to clean any promise that may be stored in PeerConnectionBackend.

The goal of this is to be more aligned with https://www.w3.org/TR/webrtc/.
Implementation of the various functions such as //www.w3.org/TR/webrtc/#set-description would be done in PeerConnectionBackend.
This will require additional code moved from MediaEndpointPeerConnection up to PeerConnectionBackend.

* Modules/mediastream/MediaEndpointPeerConnection.cpp:
(WebCore::MediaEndpointPeerConnection::createOfferTask):
(WebCore::MediaEndpointPeerConnection::doCreateAnswer):
(WebCore::MediaEndpointPeerConnection::createAnswerTask):
(WebCore::MediaEndpointPeerConnection::doSetLocalDescription):
(WebCore::MediaEndpointPeerConnection::setLocalDescriptionTask):
(WebCore::MediaEndpointPeerConnection::doSetRemoteDescription):
(WebCore::MediaEndpointPeerConnection::setRemoteDescriptionTask):
(WebCore::MediaEndpointPeerConnection::doAddIceCandidate):
(WebCore::MediaEndpointPeerConnection::addIceCandidateTask):
(WebCore::MediaEndpointPeerConnection::doStop):
(WebCore::MediaEndpointPeerConnection::gotIceCandidate):
(WebCore::MediaEndpointPeerConnection::doneGatheringCandidates):
(WebCore::MediaEndpointPeerConnection::createAnswer): Deleted.
(WebCore::MediaEndpointPeerConnection::setLocalDescription): Deleted.
(WebCore::MediaEndpointPeerConnection::setRemoteDescription): Deleted.
(WebCore::MediaEndpointPeerConnection::addIceCandidate): Deleted.
(WebCore::MediaEndpointPeerConnection::stop): Deleted.
(WebCore::MediaEndpointPeerConnection::localDescriptionTypeValidForState): Deleted.
(WebCore::MediaEndpointPeerConnection::remoteDescriptionTypeValidForState): Deleted.
* Modules/mediastream/MediaEndpointPeerConnection.h:
* Modules/mediastream/PeerConnectionBackend.cpp:
(WebCore::PeerConnectionBackend::createOffer):
(WebCore::PeerConnectionBackend::createOfferFailed):
(WebCore::PeerConnectionBackend::createAnswer):
(WebCore::PeerConnectionBackend::createAnswerSucceeded):
(WebCore::PeerConnectionBackend::createAnswerFailed):
(WebCore::isLocalDescriptionTypeValidForState):
(WebCore::PeerConnectionBackend::setLocalDescription):
(WebCore::PeerConnectionBackend::setLocalDescriptionSucceeded):
(WebCore::PeerConnectionBackend::setLocalDescriptionFailed):
(WebCore::isRemoteDescriptionTypeValidForState):
(WebCore::PeerConnectionBackend::setRemoteDescription):
(WebCore::PeerConnectionBackend::setRemoteDescriptionSucceeded):
(WebCore::PeerConnectionBackend::setRemoteDescriptionFailed):
(WebCore::PeerConnectionBackend::addIceCandidate):
(WebCore::PeerConnectionBackend::addIceCandidateSucceeded):
(WebCore::PeerConnectionBackend::addIceCandidateFailed):
(WebCore::PeerConnectionBackend::fireICECandidateEvent):
(WebCore::PeerConnectionBackend::doneGatheringCandidates):
(WebCore::PeerConnectionBackend::stop):
* Modules/mediastream/PeerConnectionBackend.h:

LayoutTests:

Rebasing test as patch changes the order in which error cases are checked in case of setRemoteDescription/setLocalDescription.
New order tries to follow more closely https://www.w3.org/TR/webrtc/#set-description.

* fast/mediastream/RTCPeerConnection-stable-expected.txt:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsfastmediastreamRTCPeerConnectionstableexpectedtxt">trunk/LayoutTests/fast/mediastream/RTCPeerConnection-stable-expected.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesmediastreamMediaEndpointPeerConnectioncpp">trunk/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesmediastreamMediaEndpointPeerConnectionh">trunk/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.h</a></li>
<li><a href="#trunkSourceWebCoreModulesmediastreamPeerConnectionBackendcpp">trunk/Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesmediastreamPeerConnectionBackendh">trunk/Source/WebCore/Modules/mediastream/PeerConnectionBackend.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (208444 => 208445)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-11-09 18:27:37 UTC (rev 208444)
+++ trunk/LayoutTests/ChangeLog        2016-11-09 18:28:08 UTC (rev 208445)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2016-11-09  Youenn Fablet  &lt;youenn@apple.com&gt;
+
+        [WebRTC] Introduce asynchronous backend for other RTCPeerConnection API
+        https://bugs.webkit.org/show_bug.cgi?id=164409
+
+        Reviewed by Eric Carlson.
+
+        Rebasing test as patch changes the order in which error cases are checked in case of setRemoteDescription/setLocalDescription.
+        New order tries to follow more closely https://www.w3.org/TR/webrtc/#set-description.
+
+        * fast/mediastream/RTCPeerConnection-stable-expected.txt:
+
</ins><span class="cx"> 2016-11-09  Joanmarie Diggs  &lt;jdiggs@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         AX: [ATK] Wrong selected element at a given index in a list box (redux)
</span></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamRTCPeerConnectionstableexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/mediastream/RTCPeerConnection-stable-expected.txt (208444 => 208445)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/RTCPeerConnection-stable-expected.txt        2016-11-09 18:27:37 UTC (rev 208444)
+++ trunk/LayoutTests/fast/mediastream/RTCPeerConnection-stable-expected.txt        2016-11-09 18:28:08 UTC (rev 208445)
</span><span class="lines">@@ -6,25 +6,25 @@
</span><span class="cx"> PASS pc.signalingState is &quot;stable&quot;
</span><span class="cx"> PASS pc.setLocalDescription(sessionDescription, finishIfSucceeded, requestFailed1); did not throw exception.
</span><span class="cx"> PASS setLocalDescription failed.
</span><del>-FAIL errorReason.name should be InvalidSessionDescriptionError. Was InvalidAccessError.
</del><ins>+FAIL errorReason.name should be InvalidSessionDescriptionError. Was InvalidStateError.
</ins><span class="cx"> FAIL pc.localDescription should throw an exception. Was null.
</span><span class="cx"> FAIL pc.remoteDescription should throw an exception. Was null.
</span><span class="cx"> PASS pc.signalingState is &quot;stable&quot;
</span><span class="cx"> PASS pc.setLocalDescription(sessionDescription, finishIfSucceeded, requestFailed2); did not throw exception.
</span><span class="cx"> PASS setLocalDescription failed.
</span><del>-FAIL errorReason.name should be InvalidSessionDescriptionError. Was InvalidAccessError.
</del><ins>+FAIL errorReason.name should be InvalidSessionDescriptionError. Was InvalidStateError.
</ins><span class="cx"> FAIL pc.localDescription should throw an exception. Was null.
</span><span class="cx"> FAIL pc.remoteDescription should throw an exception. Was null.
</span><span class="cx"> PASS pc.signalingState is &quot;stable&quot;
</span><span class="cx"> PASS pc.setRemoteDescription(sessionDescription, finishIfSucceeded, requestFailed3); did not throw exception.
</span><span class="cx"> PASS setRemoteDescription failed.
</span><del>-FAIL errorReason.name should be InvalidSessionDescriptionError. Was InvalidAccessError.
</del><ins>+FAIL errorReason.name should be InvalidSessionDescriptionError. Was InvalidStateError.
</ins><span class="cx"> FAIL pc.localDescription should throw an exception. Was null.
</span><span class="cx"> FAIL pc.remoteDescription should throw an exception. Was null.
</span><span class="cx"> PASS pc.signalingState is &quot;stable&quot;
</span><span class="cx"> PASS pc.setRemoteDescription(sessionDescription, finishIfSucceeded, requestFailed4); did not throw exception.
</span><span class="cx"> PASS setRemoteDescription failed.
</span><del>-FAIL errorReason.name should be InvalidSessionDescriptionError. Was InvalidAccessError.
</del><ins>+FAIL errorReason.name should be InvalidSessionDescriptionError. Was InvalidStateError.
</ins><span class="cx"> FAIL pc.localDescription should throw an exception. Was null.
</span><span class="cx"> FAIL pc.remoteDescription should throw an exception. Was null.
</span><span class="cx"> PASS pc.signalingState is &quot;stable&quot;
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (208444 => 208445)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-11-09 18:27:37 UTC (rev 208444)
+++ trunk/Source/WebCore/ChangeLog        2016-11-09 18:28:08 UTC (rev 208445)
</span><span class="lines">@@ -1,3 +1,63 @@
</span><ins>+2016-11-09  Youenn Fablet  &lt;youenn@apple.com&gt;
+
+        [WebRTC] Introduce asynchronous backend for other RTCPeerConnection API
+        https://bugs.webkit.org/show_bug.cgi?id=164409
+
+        Reviewed by Eric Carlson.
+
+        Covered by existing tests.
+
+        Following on createOffer changes, applying the same changes to createAnswer, setLocalDescription, setRemoteDescription and addIceCandidate.
+        Also refactored ICE candidate event generation (done at PeerConnectionBackend).
+        Updated stop implementation to clean any promise that may be stored in PeerConnectionBackend.
+
+        The goal of this is to be more aligned with https://www.w3.org/TR/webrtc/.
+        Implementation of the various functions such as //www.w3.org/TR/webrtc/#set-description would be done in PeerConnectionBackend.
+        This will require additional code moved from MediaEndpointPeerConnection up to PeerConnectionBackend.
+
+        * Modules/mediastream/MediaEndpointPeerConnection.cpp:
+        (WebCore::MediaEndpointPeerConnection::createOfferTask):
+        (WebCore::MediaEndpointPeerConnection::doCreateAnswer):
+        (WebCore::MediaEndpointPeerConnection::createAnswerTask):
+        (WebCore::MediaEndpointPeerConnection::doSetLocalDescription):
+        (WebCore::MediaEndpointPeerConnection::setLocalDescriptionTask):
+        (WebCore::MediaEndpointPeerConnection::doSetRemoteDescription):
+        (WebCore::MediaEndpointPeerConnection::setRemoteDescriptionTask):
+        (WebCore::MediaEndpointPeerConnection::doAddIceCandidate):
+        (WebCore::MediaEndpointPeerConnection::addIceCandidateTask):
+        (WebCore::MediaEndpointPeerConnection::doStop):
+        (WebCore::MediaEndpointPeerConnection::gotIceCandidate):
+        (WebCore::MediaEndpointPeerConnection::doneGatheringCandidates):
+        (WebCore::MediaEndpointPeerConnection::createAnswer): Deleted.
+        (WebCore::MediaEndpointPeerConnection::setLocalDescription): Deleted.
+        (WebCore::MediaEndpointPeerConnection::setRemoteDescription): Deleted.
+        (WebCore::MediaEndpointPeerConnection::addIceCandidate): Deleted.
+        (WebCore::MediaEndpointPeerConnection::stop): Deleted.
+        (WebCore::MediaEndpointPeerConnection::localDescriptionTypeValidForState): Deleted.
+        (WebCore::MediaEndpointPeerConnection::remoteDescriptionTypeValidForState): Deleted.
+        * Modules/mediastream/MediaEndpointPeerConnection.h:
+        * Modules/mediastream/PeerConnectionBackend.cpp:
+        (WebCore::PeerConnectionBackend::createOffer):
+        (WebCore::PeerConnectionBackend::createOfferFailed):
+        (WebCore::PeerConnectionBackend::createAnswer):
+        (WebCore::PeerConnectionBackend::createAnswerSucceeded):
+        (WebCore::PeerConnectionBackend::createAnswerFailed):
+        (WebCore::isLocalDescriptionTypeValidForState):
+        (WebCore::PeerConnectionBackend::setLocalDescription):
+        (WebCore::PeerConnectionBackend::setLocalDescriptionSucceeded):
+        (WebCore::PeerConnectionBackend::setLocalDescriptionFailed):
+        (WebCore::isRemoteDescriptionTypeValidForState):
+        (WebCore::PeerConnectionBackend::setRemoteDescription):
+        (WebCore::PeerConnectionBackend::setRemoteDescriptionSucceeded):
+        (WebCore::PeerConnectionBackend::setRemoteDescriptionFailed):
+        (WebCore::PeerConnectionBackend::addIceCandidate):
+        (WebCore::PeerConnectionBackend::addIceCandidateSucceeded):
+        (WebCore::PeerConnectionBackend::addIceCandidateFailed):
+        (WebCore::PeerConnectionBackend::fireICECandidateEvent):
+        (WebCore::PeerConnectionBackend::doneGatheringCandidates):
+        (WebCore::PeerConnectionBackend::stop):
+        * Modules/mediastream/PeerConnectionBackend.h:
+
</ins><span class="cx"> 2016-11-09  Eric Carlson  &lt;eric.carlson@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [MediaStream][Mac] Mark captured video frames as ready for display immediately
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediastreamMediaEndpointPeerConnectioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp (208444 => 208445)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp        2016-11-09 18:27:37 UTC (rev 208444)
+++ trunk/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp        2016-11-09 18:28:08 UTC (rev 208445)
</span><span class="lines">@@ -204,28 +204,25 @@
</span><span class="cx">     String sdp;
</span><span class="cx">     SDPProcessor::Result result = m_sdpProcessor-&gt;generate(*configurationSnapshot, sdp);
</span><span class="cx">     if (result != SDPProcessor::Result::Success) {
</span><del>-        createOfferFailed(OperationError, &quot;SDPProcessor internal error&quot;);
</del><ins>+        createOfferFailed(Exception { OperationError, &quot;SDPProcessor internal error&quot; });
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     createOfferSucceeded(WTFMove(sdp));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MediaEndpointPeerConnection::createAnswer(RTCAnswerOptions&amp;&amp; options, SessionDescriptionPromise&amp;&amp; promise)
</del><ins>+void MediaEndpointPeerConnection::doCreateAnswer(RTCAnswerOptions&amp;&amp; options)
</ins><span class="cx"> {
</span><del>-    runTask([this, protectedOptions = WTFMove(options), protectedPromise = WTFMove(promise)]() mutable {
-        createAnswerTask(protectedOptions, protectedPromise);
</del><ins>+    runTask([this, protectedOptions = WTFMove(options)]() mutable {
+        createAnswerTask(protectedOptions);
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MediaEndpointPeerConnection::createAnswerTask(const RTCAnswerOptions&amp;, SessionDescriptionPromise&amp; promise)
</del><ins>+void MediaEndpointPeerConnection::createAnswerTask(const RTCAnswerOptions&amp;)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!m_dtlsFingerprint.isEmpty());
</span><span class="cx"> 
</span><del>-    if (m_peerConnection.internalSignalingState() == SignalingState::Closed)
-        return;
-
</del><span class="cx">     if (!internalRemoteDescription()) {
</span><del>-        promise.reject(INVALID_STATE_ERR, &quot;No remote description set&quot;);
</del><ins>+        createAnswerFailed(Exception { INVALID_STATE_ERR, &quot;No remote description set&quot; });
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -289,8 +286,13 @@
</span><span class="cx">     if (hasUnassociatedTransceivers(transceivers))
</span><span class="cx">         markAsNeedingNegotiation();
</span><span class="cx"> 
</span><del>-    auto description = MediaEndpointSessionDescription::create(RTCSessionDescription::SdpType::Answer, WTFMove(configurationSnapshot));
-    promise.resolve(*description-&gt;toRTCSessionDescription(*m_sdpProcessor));
</del><ins>+    String sdp;
+    SDPProcessor::Result result = m_sdpProcessor-&gt;generate(*configurationSnapshot, sdp);
+    if (result != SDPProcessor::Result::Success) {
+        createAnswerFailed(Exception { OperationError, &quot;SDPProcessor internal error&quot; });
+        return;
+    }
+    createAnswerSucceeded(WTFMove(sdp));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static RealtimeMediaSourceMap createSourceMap(const MediaDescriptionVector&amp; remoteMediaDescriptions, unsigned localMediaDescriptionCount, const RtpTransceiverVector&amp; transceivers)
</span><span class="lines">@@ -312,14 +314,14 @@
</span><span class="cx">     return sourceMap;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MediaEndpointPeerConnection::setLocalDescription(RTCSessionDescription&amp; description, VoidPromise&amp;&amp; promise)
</del><ins>+void MediaEndpointPeerConnection::doSetLocalDescription(RTCSessionDescription&amp; description)
</ins><span class="cx"> {
</span><del>-    runTask([this, protectedDescription = RefPtr&lt;RTCSessionDescription&gt;(&amp;description), protectedPromise = WTFMove(promise)]() mutable {
-        setLocalDescriptionTask(WTFMove(protectedDescription), protectedPromise);
</del><ins>+    runTask([this, protectedDescription = RefPtr&lt;RTCSessionDescription&gt;(&amp;description)]() mutable {
+        setLocalDescriptionTask(WTFMove(protectedDescription));
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MediaEndpointPeerConnection::setLocalDescriptionTask(RefPtr&lt;RTCSessionDescription&gt;&amp;&amp; description, VoidPromise&amp; promise)
</del><ins>+void MediaEndpointPeerConnection::setLocalDescriptionTask(RefPtr&lt;RTCSessionDescription&gt;&amp;&amp; description)
</ins><span class="cx"> {
</span><span class="cx">     if (m_peerConnection.internalSignalingState() == SignalingState::Closed)
</span><span class="cx">         return;
</span><span class="lines">@@ -326,16 +328,11 @@
</span><span class="cx"> 
</span><span class="cx">     auto result = MediaEndpointSessionDescription::create(WTFMove(description), *m_sdpProcessor);
</span><span class="cx">     if (result.hasException()) {
</span><del>-        promise.reject(result.releaseException());
</del><ins>+        setLocalDescriptionFailed(result.releaseException());
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     auto newDescription = result.releaseReturnValue();
</span><span class="cx"> 
</span><del>-    if (!localDescriptionTypeValidForState(newDescription-&gt;type())) {
-        promise.reject(INVALID_STATE_ERR, &quot;Description type incompatible with current signaling state&quot;);
-        return;
-    }
-
</del><span class="cx">     const RtpTransceiverVector&amp; transceivers = m_peerConnection.getTransceivers();
</span><span class="cx">     const MediaDescriptionVector&amp; mediaDescriptions = newDescription-&gt;configuration()-&gt;mediaDescriptions();
</span><span class="cx">     MediaEndpointSessionDescription* localDescription = internalLocalDescription();
</span><span class="lines">@@ -357,7 +354,7 @@
</span><span class="cx">             notImplemented();
</span><span class="cx"> 
</span><span class="cx">         } else if (result == MediaEndpoint::UpdateResult::Failed) {
</span><del>-            promise.reject(OperationError, &quot;Unable to apply session description&quot;);
</del><ins>+            setLocalDescriptionFailed(Exception { OperationError, &quot;Unable to apply session description&quot; });
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -376,7 +373,7 @@
</span><span class="cx">         RealtimeMediaSourceMap sendSourceMap = createSourceMap(remoteConfiguration-&gt;mediaDescriptions(), mediaDescriptions.size(), transceivers);
</span><span class="cx"> 
</span><span class="cx">         if (m_mediaEndpoint-&gt;updateSendConfiguration(remoteConfiguration, sendSourceMap, isInitiator) == MediaEndpoint::UpdateResult::Failed) {
</span><del>-            promise.reject(OperationError, &quot;Unable to apply session description&quot;);
</del><ins>+            setLocalDescriptionFailed(Exception { OperationError, &quot;Unable to apply session description&quot; });
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -423,7 +420,7 @@
</span><span class="cx">     if (m_peerConnection.internalSignalingState() == SignalingState::Stable &amp;&amp; m_negotiationNeeded)
</span><span class="cx">         m_peerConnection.scheduleNegotiationNeededEvent();
</span><span class="cx"> 
</span><del>-    promise.resolve(nullptr);
</del><ins>+    setLocalDescriptionSucceeded();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> RefPtr&lt;RTCSessionDescription&gt; MediaEndpointPeerConnection::localDescription() const
</span><span class="lines">@@ -441,30 +438,22 @@
</span><span class="cx">     return createRTCSessionDescription(m_pendingLocalDescription.get());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MediaEndpointPeerConnection::setRemoteDescription(RTCSessionDescription&amp; description, VoidPromise&amp;&amp; promise)
</del><ins>+void MediaEndpointPeerConnection::doSetRemoteDescription(RTCSessionDescription&amp; description)
</ins><span class="cx"> {
</span><del>-    runTask([this, protectedDescription = RefPtr&lt;RTCSessionDescription&gt;(&amp;description), protectedPromise = WTFMove(promise)]() mutable {
-        setRemoteDescriptionTask(WTFMove(protectedDescription), protectedPromise);
</del><ins>+    runTask([this, protectedDescription = RefPtr&lt;RTCSessionDescription&gt;(&amp;description)]() mutable {
+        setRemoteDescriptionTask(WTFMove(protectedDescription));
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MediaEndpointPeerConnection::setRemoteDescriptionTask(RefPtr&lt;RTCSessionDescription&gt;&amp;&amp; description, VoidPromise&amp; promise)
</del><ins>+void MediaEndpointPeerConnection::setRemoteDescriptionTask(RefPtr&lt;RTCSessionDescription&gt;&amp;&amp; description)
</ins><span class="cx"> {
</span><del>-    if (m_peerConnection.internalSignalingState() == SignalingState::Closed)
-        return;
-
</del><span class="cx">     auto result = MediaEndpointSessionDescription::create(WTFMove(description), *m_sdpProcessor);
</span><span class="cx">     if (result.hasException()) {
</span><del>-        promise.reject(result.releaseException());
</del><ins>+        setRemoteDescriptionFailed(result.releaseException());
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     auto newDescription = result.releaseReturnValue();
</span><span class="cx"> 
</span><del>-    if (!remoteDescriptionTypeValidForState(newDescription-&gt;type())) {
-        promise.reject(INVALID_STATE_ERR, &quot;Description type incompatible with current signaling state&quot;);
-        return;
-    }
-
</del><span class="cx">     auto&amp; mediaDescriptions = newDescription-&gt;configuration()-&gt;mediaDescriptions();
</span><span class="cx">     for (auto&amp; mediaDescription : mediaDescriptions) {
</span><span class="cx">         if (mediaDescription.type != &quot;audio&quot; &amp;&amp; mediaDescription.type != &quot;video&quot;)
</span><span class="lines">@@ -481,7 +470,7 @@
</span><span class="cx">         sendSourceMap = createSourceMap(mediaDescriptions, internalLocalDescription()-&gt;configuration()-&gt;mediaDescriptions().size(), transceivers);
</span><span class="cx"> 
</span><span class="cx">     if (m_mediaEndpoint-&gt;updateSendConfiguration(newDescription-&gt;configuration(), sendSourceMap, isInitiator) == MediaEndpoint::UpdateResult::Failed) {
</span><del>-        promise.reject(OperationError, &quot;Unable to apply session description&quot;);
</del><ins>+        setRemoteDescriptionFailed(Exception { OperationError, &quot;Unable to apply session description&quot; });
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -594,7 +583,7 @@
</span><span class="cx">         m_peerConnection.fireEvent(Event::create(eventNames().signalingstatechangeEvent, false, false));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    promise.resolve(nullptr);
</del><ins>+    setRemoteDescriptionSucceeded();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> RefPtr&lt;RTCSessionDescription&gt; MediaEndpointPeerConnection::remoteDescription() const
</span><span class="lines">@@ -629,20 +618,17 @@
</span><span class="cx">     m_mediaEndpoint-&gt;setConfiguration({ WTFMove(iceServers), configuration.iceTransportPolicy(), configuration.bundlePolicy() });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MediaEndpointPeerConnection::addIceCandidate(RTCIceCandidate&amp; rtcCandidate, PeerConnection::VoidPromise&amp;&amp; promise)
</del><ins>+void MediaEndpointPeerConnection::doAddIceCandidate(RTCIceCandidate&amp; rtcCandidate)
</ins><span class="cx"> {
</span><del>-    runTask([this, protectedCandidate = RefPtr&lt;RTCIceCandidate&gt;(&amp;rtcCandidate), protectedPromise = WTFMove(promise)]() mutable {
-        addIceCandidateTask(*protectedCandidate, protectedPromise);
</del><ins>+    runTask([this, protectedCandidate = RefPtr&lt;RTCIceCandidate&gt;(&amp;rtcCandidate)]() mutable {
+        addIceCandidateTask(*protectedCandidate);
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MediaEndpointPeerConnection::addIceCandidateTask(RTCIceCandidate&amp; rtcCandidate, PeerConnection::VoidPromise&amp; promise)
</del><ins>+void MediaEndpointPeerConnection::addIceCandidateTask(RTCIceCandidate&amp; rtcCandidate)
</ins><span class="cx"> {
</span><del>-    if (m_peerConnection.internalSignalingState() == SignalingState::Closed)
-        return;
-
</del><span class="cx">     if (!internalRemoteDescription()) {
</span><del>-        promise.reject(INVALID_STATE_ERR, &quot;No remote description set&quot;);
</del><ins>+        addIceCandidateFailed(Exception { INVALID_STATE_ERR, &quot;No remote description set&quot; });
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -661,13 +647,13 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (!targetMediaDescription) {
</span><del>-            promise.reject(OperationError, &quot;sdpMid did not match any media description&quot;);
</del><ins>+            addIceCandidateFailed(Exception { OperationError, &quot;sdpMid did not match any media description&quot; });
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">     } else if (rtcCandidate.sdpMLineIndex()) {
</span><span class="cx">         unsigned short sdpMLineIndex = rtcCandidate.sdpMLineIndex().value();
</span><span class="cx">         if (sdpMLineIndex &gt;= remoteMediaDescriptions.size()) {
</span><del>-            promise.reject(OperationError, &quot;sdpMLineIndex is out of range&quot;);
</del><ins>+            addIceCandidateFailed(Exception { OperationError, &quot;sdpMLineIndex is out of range&quot; });
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         targetMediaDescription = &amp;remoteMediaDescriptions[sdpMLineIndex];
</span><span class="lines">@@ -679,7 +665,7 @@
</span><span class="cx">     auto result = m_sdpProcessor-&gt;parseCandidateLine(rtcCandidate.candidate());
</span><span class="cx">     if (result.parsingStatus() != SDPProcessor::Result::Success) {
</span><span class="cx">         if (result.parsingStatus() == SDPProcessor::Result::ParseError)
</span><del>-            promise.reject(OperationError, &quot;Invalid candidate content&quot;);
</del><ins>+            addIceCandidateFailed(Exception { OperationError, &quot;Invalid candidate content&quot; });
</ins><span class="cx">         else
</span><span class="cx">             LOG_ERROR(&quot;SDPProcessor internal error&quot;);
</span><span class="cx">         return;
</span><span class="lines">@@ -690,7 +676,7 @@
</span><span class="cx"> 
</span><span class="cx">     targetMediaDescription-&gt;addIceCandidate(WTFMove(result.candidate()));
</span><span class="cx"> 
</span><del>-    promise.resolve(nullptr);
</del><ins>+    addIceCandidateSucceeded();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void MediaEndpointPeerConnection::getStats(MediaStreamTrack*, PeerConnection::StatsPromise&amp;&amp; promise)
</span><span class="lines">@@ -750,7 +736,7 @@
</span><span class="cx">     promise.resolve(nullptr);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MediaEndpointPeerConnection::stop()
</del><ins>+void MediaEndpointPeerConnection::doStop()
</ins><span class="cx"> {
</span><span class="cx">     m_mediaEndpoint-&gt;stop();
</span><span class="cx"> }
</span><span class="lines">@@ -771,44 +757,6 @@
</span><span class="cx">     m_mediaEndpoint-&gt;emulatePlatformEvent(action);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool MediaEndpointPeerConnection::localDescriptionTypeValidForState(RTCSessionDescription::SdpType type) const
-{
-    switch (m_peerConnection.internalSignalingState()) {
-    case SignalingState::Stable:
-        return type == RTCSessionDescription::SdpType::Offer;
-    case SignalingState::HaveLocalOffer:
-        return type == RTCSessionDescription::SdpType::Offer;
-    case SignalingState::HaveRemoteOffer:
-        return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer;
-    case SignalingState::HaveLocalPrAnswer:
-        return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer;
-    default:
-        return false;
-    };
-
-    ASSERT_NOT_REACHED();
-    return false;
-}
-
-bool MediaEndpointPeerConnection::remoteDescriptionTypeValidForState(RTCSessionDescription::SdpType type) const
-{
-    switch (m_peerConnection.internalSignalingState()) {
-    case SignalingState::Stable:
-        return type == RTCSessionDescription::SdpType::Offer;
-    case SignalingState::HaveLocalOffer:
-        return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer;
-    case SignalingState::HaveRemoteOffer:
-        return type == RTCSessionDescription::SdpType::Offer;
-    case SignalingState::HaveRemotePrAnswer:
-        return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer;
-    default:
-        return false;
-    };
-
-    ASSERT_NOT_REACHED();
-    return false;
-}
-
</del><span class="cx"> MediaEndpointSessionDescription* MediaEndpointPeerConnection::internalLocalDescription() const
</span><span class="cx"> {
</span><span class="cx">     return m_pendingLocalDescription ? m_pendingLocalDescription.get() : m_currentLocalDescription.get();
</span><span class="lines">@@ -858,7 +806,7 @@
</span><span class="cx"> 
</span><span class="cx">     mediaDescriptions[mediaDescriptionIndex].addIceCandidate(WTFMove(candidate));
</span><span class="cx"> 
</span><del>-    m_peerConnection.fireEvent(RTCIceCandidateEvent::create(false, false, RTCIceCandidate::create(candidateLine, mid, mediaDescriptionIndex)));
</del><ins>+    fireICECandidateEvent(RTCIceCandidate::create(candidateLine, mid, mediaDescriptionIndex));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void MediaEndpointPeerConnection::doneGatheringCandidates(const String&amp; mid)
</span><span class="lines">@@ -876,10 +824,8 @@
</span><span class="cx">         return !current.stopped() &amp;&amp; !current.mid().isNull()
</span><span class="cx">             &amp;&amp; current.iceTransport().gatheringState() != RTCIceTransport::GatheringState::Complete;
</span><span class="cx">     });
</span><del>-    if (!stillGatheringTransceiver) {
-        m_peerConnection.fireEvent(RTCIceCandidateEvent::create(false, false, nullptr));
-        m_peerConnection.updateIceGatheringState(IceGatheringState::Complete);
-    }
</del><ins>+    if (!stillGatheringTransceiver)
+        PeerConnectionBackend::doneGatheringCandidates();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static RTCIceTransport::TransportState deriveAggregatedIceConnectionState(const Vector&lt;RTCIceTransport::TransportState&gt;&amp; states)
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediastreamMediaEndpointPeerConnectionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.h (208444 => 208445)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.h        2016-11-09 18:27:37 UTC (rev 208444)
+++ trunk/Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.h        2016-11-09 18:28:08 UTC (rev 208445)
</span><span class="lines">@@ -54,21 +54,15 @@
</span><span class="cx"> public:
</span><span class="cx">     MediaEndpointPeerConnection(RTCPeerConnection&amp;);
</span><span class="cx"> 
</span><del>-    void doCreateOffer(RTCOfferOptions&amp;&amp;) final;
-    void createAnswer(RTCAnswerOptions&amp;&amp;, PeerConnection::SessionDescriptionPromise&amp;&amp;) override;
-
-    void setLocalDescription(RTCSessionDescription&amp;, PeerConnection::VoidPromise&amp;&amp;) override;
</del><span class="cx">     RefPtr&lt;RTCSessionDescription&gt; localDescription() const override;
</span><span class="cx">     RefPtr&lt;RTCSessionDescription&gt; currentLocalDescription() const override;
</span><span class="cx">     RefPtr&lt;RTCSessionDescription&gt; pendingLocalDescription() const override;
</span><span class="cx"> 
</span><del>-    void setRemoteDescription(RTCSessionDescription&amp;, PeerConnection::VoidPromise&amp;&amp;) override;
</del><span class="cx">     RefPtr&lt;RTCSessionDescription&gt; remoteDescription() const override;
</span><span class="cx">     RefPtr&lt;RTCSessionDescription&gt; currentRemoteDescription() const override;
</span><span class="cx">     RefPtr&lt;RTCSessionDescription&gt; pendingRemoteDescription() const override;
</span><span class="cx"> 
</span><span class="cx">     void setConfiguration(RTCConfiguration&amp;) override;
</span><del>-    void addIceCandidate(RTCIceCandidate&amp;, PeerConnection::VoidPromise&amp;&amp;) override;
</del><span class="cx"> 
</span><span class="cx">     void getStats(MediaStreamTrack*, PeerConnection::StatsPromise&amp;&amp;) override;
</span><span class="cx"> 
</span><span class="lines">@@ -77,8 +71,6 @@
</span><span class="cx">     RefPtr&lt;RTCRtpReceiver&gt; createReceiver(const String&amp; transceiverMid, const String&amp; trackKind, const String&amp; trackId) override;
</span><span class="cx">     void replaceTrack(RTCRtpSender&amp;, RefPtr&lt;MediaStreamTrack&gt;&amp;&amp;, PeerConnection::VoidPromise&amp;&amp;) override;
</span><span class="cx"> 
</span><del>-    void stop() override;
-
</del><span class="cx">     bool isNegotiationNeeded() const override { return m_negotiationNeeded; };
</span><span class="cx">     void markAsNeedingNegotiation() override;
</span><span class="cx">     void clearNegotiationNeededState() override { m_negotiationNeeded = false; };
</span><span class="lines">@@ -89,13 +81,20 @@
</span><span class="cx">     void runTask(Function&lt;void ()&gt;&amp;&amp;);
</span><span class="cx">     void startRunningTasks();
</span><span class="cx"> 
</span><ins>+    void doCreateOffer(RTCOfferOptions&amp;&amp;) final;
+    void doCreateAnswer(RTCAnswerOptions&amp;&amp;) final;
+    void doSetLocalDescription(RTCSessionDescription&amp;) final;
+    void doSetRemoteDescription(RTCSessionDescription&amp;) final;
+    void doAddIceCandidate(RTCIceCandidate&amp;) final;
+    void doStop() final;
+
</ins><span class="cx">     void createOfferTask(const RTCOfferOptions&amp;);
</span><del>-    void createAnswerTask(const RTCAnswerOptions&amp;, PeerConnection::SessionDescriptionPromise&amp;);
</del><ins>+    void createAnswerTask(const RTCAnswerOptions&amp;);
</ins><span class="cx"> 
</span><del>-    void setLocalDescriptionTask(RefPtr&lt;RTCSessionDescription&gt;&amp;&amp;, PeerConnection::VoidPromise&amp;);
-    void setRemoteDescriptionTask(RefPtr&lt;RTCSessionDescription&gt;&amp;&amp;, PeerConnection::VoidPromise&amp;);
</del><ins>+    void setLocalDescriptionTask(RefPtr&lt;RTCSessionDescription&gt;&amp;&amp;);
+    void setRemoteDescriptionTask(RefPtr&lt;RTCSessionDescription&gt;&amp;&amp;);
</ins><span class="cx"> 
</span><del>-    void addIceCandidateTask(RTCIceCandidate&amp;, PeerConnection::VoidPromise&amp;);
</del><ins>+    void addIceCandidateTask(RTCIceCandidate&amp;);
</ins><span class="cx"> 
</span><span class="cx">     void replaceTrackTask(RTCRtpSender&amp;, const String&amp; mid, RefPtr&lt;MediaStreamTrack&gt;&amp;&amp;, PeerConnection::VoidPromise&amp;);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediastreamPeerConnectionBackendcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp (208444 => 208445)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp        2016-11-09 18:27:37 UTC (rev 208444)
+++ trunk/Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp        2016-11-09 18:28:08 UTC (rev 208445)
</span><span class="lines">@@ -35,6 +35,8 @@
</span><span class="cx"> #if ENABLE(WEB_RTC)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;JSRTCSessionDescription.h&quot;
</span><ins>+#include &quot;RTCIceCandidate.h&quot;
+#include &quot;RTCIceCandidateEvent.h&quot;
</ins><span class="cx"> #include &quot;RTCPeerConnection.h&quot;
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="lines">@@ -42,10 +44,8 @@
</span><span class="cx"> void PeerConnectionBackend::createOffer(RTCOfferOptions&amp;&amp; options, PeerConnection::SessionDescriptionPromise&amp;&amp; promise)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!m_offerAnswerPromise);
</span><ins>+    ASSERT(m_peerConnection.internalSignalingState() != PeerConnectionStates::SignalingState::Closed);
</ins><span class="cx"> 
</span><del>-    if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed)
-        return;
-
</del><span class="cx">     m_offerAnswerPromise = WTFMove(promise);
</span><span class="cx">     doCreateOffer(WTFMove(options));
</span><span class="cx"> }
</span><span class="lines">@@ -62,7 +62,7 @@
</span><span class="cx">     m_offerAnswerPromise = Nullopt;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void PeerConnectionBackend::createOfferFailed(ExceptionCode ec, String&amp;&amp; error)
</del><ins>+void PeerConnectionBackend::createOfferFailed(Exception&amp;&amp; exception)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx"> 
</span><span class="lines">@@ -70,10 +70,221 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     ASSERT(m_offerAnswerPromise);
</span><del>-    m_offerAnswerPromise-&gt;reject(ec, WTFMove(error));
</del><ins>+    m_offerAnswerPromise-&gt;reject(WTFMove(exception));
</ins><span class="cx">     m_offerAnswerPromise = Nullopt;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void PeerConnectionBackend::createAnswer(RTCAnswerOptions&amp;&amp; options, PeerConnection::SessionDescriptionPromise&amp;&amp; promise)
+{
+    ASSERT(!m_offerAnswerPromise);
+    ASSERT(m_peerConnection.internalSignalingState() != PeerConnectionStates::SignalingState::Closed);
+
+    m_offerAnswerPromise = WTFMove(promise);
+    doCreateAnswer(WTFMove(options));
+}
+
+void PeerConnectionBackend::createAnswerSucceeded(String&amp;&amp; sdp)
+{
+    ASSERT(isMainThread());
+
+    if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed)
+        return;
+
+    ASSERT(m_offerAnswerPromise);
+    m_offerAnswerPromise-&gt;resolve(RTCSessionDescription::create(RTCSessionDescription::SdpType::Answer, WTFMove(sdp)));
+    m_offerAnswerPromise = Nullopt;
+}
+
+void PeerConnectionBackend::createAnswerFailed(Exception&amp;&amp; exception)
+{
+    ASSERT(isMainThread());
+
+    if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed)
+        return;
+
+    ASSERT(m_offerAnswerPromise);
+    m_offerAnswerPromise-&gt;reject(WTFMove(exception));
+    m_offerAnswerPromise = Nullopt;
+}
+
+static inline bool isLocalDescriptionTypeValidForState(RTCSessionDescription::SdpType type, PeerConnectionStates::SignalingState state)
+{
+    switch (state) {
+    case PeerConnectionStates::SignalingState::Stable:
+        return type == RTCSessionDescription::SdpType::Offer;
+    case PeerConnectionStates::SignalingState::HaveLocalOffer:
+        return type == RTCSessionDescription::SdpType::Offer;
+    case PeerConnectionStates::SignalingState::HaveRemoteOffer:
+        return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer;
+    case PeerConnectionStates::SignalingState::HaveLocalPrAnswer:
+        return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer;
+    default:
+        return false;
+    };
+
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
+void PeerConnectionBackend::setLocalDescription(RTCSessionDescription&amp; sessionDescription, PeerConnection::VoidPromise&amp;&amp; promise)
+{
+    ASSERT(m_peerConnection.internalSignalingState() != PeerConnectionStates::SignalingState::Closed);
+
+    if (!isLocalDescriptionTypeValidForState(sessionDescription.type(), m_peerConnection.internalSignalingState())) {
+        promise.reject(INVALID_STATE_ERR, &quot;Description type incompatible with current signaling state&quot;);
+        return;
+    }
+
+    m_setDescriptionPromise = WTFMove(promise);
+    doSetLocalDescription(sessionDescription);
+}
+
+void PeerConnectionBackend::setLocalDescriptionSucceeded()
+{
+    ASSERT(isMainThread());
+
+    if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed)
+        return;
+
+    ASSERT(m_setDescriptionPromise);
+
+    m_setDescriptionPromise-&gt;resolve(nullptr);
+    m_setDescriptionPromise = Nullopt;
+}
+
+void PeerConnectionBackend::setLocalDescriptionFailed(Exception&amp;&amp; exception)
+{
+    ASSERT(isMainThread());
+
+    if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed)
+        return;
+
+    ASSERT(m_setDescriptionPromise);
+
+    m_setDescriptionPromise-&gt;reject(WTFMove(exception));
+    m_setDescriptionPromise = Nullopt;
+}
+
+static inline bool isRemoteDescriptionTypeValidForState(RTCSessionDescription::SdpType type, PeerConnectionStates::SignalingState state)
+{
+    switch (state) {
+    case PeerConnectionStates::SignalingState::Stable:
+        return type == RTCSessionDescription::SdpType::Offer;
+    case PeerConnectionStates::SignalingState::HaveLocalOffer:
+        return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer;
+    case PeerConnectionStates::SignalingState::HaveRemoteOffer:
+        return type == RTCSessionDescription::SdpType::Offer;
+    case PeerConnectionStates::SignalingState::HaveRemotePrAnswer:
+        return type == RTCSessionDescription::SdpType::Answer || type == RTCSessionDescription::SdpType::Pranswer;
+    default:
+        return false;
+    };
+
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
+void PeerConnectionBackend::setRemoteDescription(RTCSessionDescription&amp; sessionDescription, PeerConnection::VoidPromise&amp;&amp; promise)
+{
+    ASSERT(m_peerConnection.internalSignalingState() != PeerConnectionStates::SignalingState::Closed);
+
+    if (!isRemoteDescriptionTypeValidForState(sessionDescription.type(), m_peerConnection.internalSignalingState())) {
+        promise.reject(INVALID_STATE_ERR, &quot;Description type incompatible with current signaling state&quot;);
+        return;
+    }
+
+    m_setDescriptionPromise = WTFMove(promise);
+    doSetRemoteDescription(sessionDescription);
+}
+
+void PeerConnectionBackend::setRemoteDescriptionSucceeded()
+{
+    ASSERT(isMainThread());
+
+    if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed)
+        return;
+
+    ASSERT(m_setDescriptionPromise);
+
+    m_setDescriptionPromise-&gt;resolve(nullptr);
+    m_setDescriptionPromise = Nullopt;
+}
+
+void PeerConnectionBackend::setRemoteDescriptionFailed(Exception&amp;&amp; exception)
+{
+    ASSERT(isMainThread());
+
+    if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed)
+        return;
+
+    ASSERT(m_setDescriptionPromise);
+
+    m_setDescriptionPromise-&gt;reject(WTFMove(exception));
+    m_setDescriptionPromise = Nullopt;
+}
+
+void PeerConnectionBackend::addIceCandidate(RTCIceCandidate&amp; iceCandidate, PeerConnection::VoidPromise&amp;&amp; promise)
+{
+    ASSERT(m_peerConnection.internalSignalingState() != PeerConnectionStates::SignalingState::Closed);
+
+    if (iceCandidate.sdpMid().isNull() &amp;&amp; !iceCandidate.sdpMLineIndex()) {
+        promise.reject(Exception { TypeError, ASCIILiteral(&quot;Trying to add a candidate that is missing both sdpMid and sdpMLineIndex&quot;) });
+        return;
+    }
+    m_addIceCandidatePromise = WTFMove(promise);
+    doAddIceCandidate(iceCandidate);
+}
+
+void PeerConnectionBackend::addIceCandidateSucceeded()
+{
+    ASSERT(isMainThread());
+
+    if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed)
+        return;
+
+    // FIXME: Update remote description and set ICE connection state to checking if not already done so.
+    ASSERT(m_addIceCandidatePromise);
+
+    m_addIceCandidatePromise-&gt;resolve(nullptr);
+    m_addIceCandidatePromise = Nullopt;
+}
+
+void PeerConnectionBackend::addIceCandidateFailed(Exception&amp;&amp; exception)
+{
+    ASSERT(isMainThread());
+    if (m_peerConnection.internalSignalingState() == PeerConnectionStates::SignalingState::Closed)
+        return;
+
+    ASSERT(m_addIceCandidatePromise);
+
+    m_addIceCandidatePromise-&gt;reject(WTFMove(exception));
+    m_addIceCandidatePromise = Nullopt;
+}
+
+void PeerConnectionBackend::fireICECandidateEvent(RefPtr&lt;RTCIceCandidate&gt;&amp;&amp; candidate)
+{
+    ASSERT(isMainThread());
+
+    m_peerConnection.fireEvent(RTCIceCandidateEvent::create(false, false, WTFMove(candidate)));
+}
+
+void PeerConnectionBackend::doneGatheringCandidates()
+{
+    ASSERT(isMainThread());
+
+    m_peerConnection.fireEvent(RTCIceCandidateEvent::create(false, false, nullptr));
+    m_peerConnection.updateIceGatheringState(PeerConnectionStates::IceGatheringState::Complete);
+}
+
+void PeerConnectionBackend::stop()
+{
+    m_offerAnswerPromise = Nullopt;
+    m_setDescriptionPromise = Nullopt;
+    m_addIceCandidatePromise = Nullopt;
+
+    doStop();
+}
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(WEB_RTC)
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediastreamPeerConnectionBackendh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediastream/PeerConnectionBackend.h (208444 => 208445)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediastream/PeerConnectionBackend.h        2016-11-09 18:27:37 UTC (rev 208444)
+++ trunk/Source/WebCore/Modules/mediastream/PeerConnectionBackend.h        2016-11-09 18:28:08 UTC (rev 208445)
</span><span class="lines">@@ -56,8 +56,6 @@
</span><span class="cx"> struct RTCAnswerOptions;
</span><span class="cx"> struct RTCOfferOptions;
</span><span class="cx"> 
</span><del>-using ExceptionCode = int;
-
</del><span class="cx"> namespace PeerConnection {
</span><span class="cx"> typedef DOMPromise&lt;RTCSessionDescription&gt; SessionDescriptionPromise;
</span><span class="cx"> typedef DOMPromise&lt;std::nullptr_t&gt; VoidPromise;
</span><span class="lines">@@ -74,24 +72,22 @@
</span><span class="cx">     virtual ~PeerConnectionBackend() { }
</span><span class="cx"> 
</span><span class="cx">     void createOffer(RTCOfferOptions&amp;&amp;, PeerConnection::SessionDescriptionPromise&amp;&amp;);
</span><del>-    virtual void doCreateOffer(RTCOfferOptions&amp;&amp;) = 0;
-    void createOfferSucceeded(String&amp;&amp;);
-    void createOfferFailed(ExceptionCode, String&amp;&amp;);
</del><ins>+    void createAnswer(RTCAnswerOptions&amp;&amp;, PeerConnection::SessionDescriptionPromise&amp;&amp;);
+    void setLocalDescription(RTCSessionDescription&amp;, PeerConnection::VoidPromise&amp;&amp;);
+    void setRemoteDescription(RTCSessionDescription&amp;, PeerConnection::VoidPromise&amp;&amp;);
+    void addIceCandidate(RTCIceCandidate&amp;, PeerConnection::VoidPromise&amp;&amp;);
</ins><span class="cx"> 
</span><del>-    virtual void createAnswer(RTCAnswerOptions&amp;&amp;, PeerConnection::SessionDescriptionPromise&amp;&amp;) = 0;
</del><ins>+    void stop();
</ins><span class="cx"> 
</span><del>-    virtual void setLocalDescription(RTCSessionDescription&amp;, PeerConnection::VoidPromise&amp;&amp;) = 0;
</del><span class="cx">     virtual RefPtr&lt;RTCSessionDescription&gt; localDescription() const = 0;
</span><span class="cx">     virtual RefPtr&lt;RTCSessionDescription&gt; currentLocalDescription() const = 0;
</span><span class="cx">     virtual RefPtr&lt;RTCSessionDescription&gt; pendingLocalDescription() const = 0;
</span><span class="cx"> 
</span><del>-    virtual void setRemoteDescription(RTCSessionDescription&amp;, PeerConnection::VoidPromise&amp;&amp;) = 0;
</del><span class="cx">     virtual RefPtr&lt;RTCSessionDescription&gt; remoteDescription() const = 0;
</span><span class="cx">     virtual RefPtr&lt;RTCSessionDescription&gt; currentRemoteDescription() const = 0;
</span><span class="cx">     virtual RefPtr&lt;RTCSessionDescription&gt; pendingRemoteDescription() const = 0;
</span><span class="cx"> 
</span><span class="cx">     virtual void setConfiguration(RTCConfiguration&amp;) = 0;
</span><del>-    virtual void addIceCandidate(RTCIceCandidate&amp;, PeerConnection::VoidPromise&amp;&amp;) = 0;
</del><span class="cx"> 
</span><span class="cx">     virtual void getStats(MediaStreamTrack*, PeerConnection::StatsPromise&amp;&amp;) = 0;
</span><span class="cx"> 
</span><span class="lines">@@ -100,8 +96,6 @@
</span><span class="cx">     virtual RefPtr&lt;RTCRtpReceiver&gt; createReceiver(const String&amp; transceiverMid, const String&amp; trackKind, const String&amp; trackId) = 0;
</span><span class="cx">     virtual void replaceTrack(RTCRtpSender&amp;, RefPtr&lt;MediaStreamTrack&gt;&amp;&amp;, PeerConnection::VoidPromise&amp;&amp;) = 0;
</span><span class="cx"> 
</span><del>-    virtual void stop() = 0;
-
</del><span class="cx">     virtual bool isNegotiationNeeded() const = 0;
</span><span class="cx">     virtual void markAsNeedingNegotiation() = 0;
</span><span class="cx">     virtual void clearNegotiationNeededState() = 0;
</span><span class="lines">@@ -109,8 +103,39 @@
</span><span class="cx">     virtual void emulatePlatformEvent(const String&amp; action) = 0;
</span><span class="cx"> 
</span><span class="cx"> protected:
</span><ins>+    void fireICECandidateEvent(RefPtr&lt;RTCIceCandidate&gt;&amp;&amp;);
+    void doneGatheringCandidates();
+
+    void createOfferSucceeded(String&amp;&amp;);
+    void createOfferFailed(Exception&amp;&amp;);
+
+    void createAnswerSucceeded(String&amp;&amp;);
+    void createAnswerFailed(Exception&amp;&amp;);
+
+    void setLocalDescriptionSucceeded();
+    void setLocalDescriptionFailed(Exception&amp;&amp;);
+
+    void setRemoteDescriptionSucceeded();
+    void setRemoteDescriptionFailed(Exception&amp;&amp;);
+
+    void addIceCandidateSucceeded();
+    void addIceCandidateFailed(Exception&amp;&amp;);
+
+private:
+    virtual void doCreateOffer(RTCOfferOptions&amp;&amp;) = 0;
+    virtual void doCreateAnswer(RTCAnswerOptions&amp;&amp;) = 0;
+    virtual void doSetLocalDescription(RTCSessionDescription&amp;) = 0;
+    virtual void doSetRemoteDescription(RTCSessionDescription&amp;) = 0;
+    virtual void doAddIceCandidate(RTCIceCandidate&amp;) = 0;
+    virtual void doStop() = 0;
+
+protected:
</ins><span class="cx">     RTCPeerConnection&amp; m_peerConnection;
</span><ins>+
+private:
</ins><span class="cx">     Optional&lt;PeerConnection::SessionDescriptionPromise&gt; m_offerAnswerPromise;
</span><ins>+    Optional&lt;PeerConnection::VoidPromise&gt; m_setDescriptionPromise;
+    Optional&lt;PeerConnection::VoidPromise&gt; m_addIceCandidatePromise;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre>
</div>
</div>

</body>
</html>