<!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>[211253] 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/211253">211253</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2017-01-26 20:54:09 -0800 (Thu, 26 Jan 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>[WebRTC] Add a LibWebRTC mock for testing
https://bugs.webkit.org/show_bug.cgi?id=167429

Patch by Youenn Fablet &lt;youennf@gmail.com&gt; on 2017-01-26
Reviewed by Alex Christensen.

Source/WebCore:

Covered by updated tests although feature is behind a flag, off by default.
MockLibWebRTCPeerConnection will allow us testing the code above the WebRTC implementation above LibWebRTC,
without reyling on it and controlling the way that the peer connections will behave.
Adding support for mock factory to create real peer connections in case where we want to do full testing through the local loopback.

Tests: fast/mediastream/getUserMedia-webaudio.html
       webrtc/datachannel/basic.html
       webrtc/video.html

* WebCore.xcodeproj/project.pbxproj:
* testing/Internals.cpp:
(WebCore::Internals::Internals):
(WebCore::Internals::useMockRTCPeerConnectionFactory):
* testing/Internals.h:
* testing/Internals.idl:
* testing/MockLibWebRTCPeerConnection.cpp: Added.
(WebCore::useMockRTCPeerConnectionFactory):
(WebCore::MockLibWebRTCPeerConnectionForIceCandidates::MockLibWebRTCPeerConnectionForIceCandidates):
(WebCore::MockLibWebRTCPeerConnectionForIceCandidates::gotLocalDescription):
(WebCore::MockLibWebRTCPeerConnectionForIceConnectionState::MockLibWebRTCPeerConnectionForIceConnectionState):
(WebCore::MockLibWebRTCPeerConnectionForIceConnectionState::gotLocalDescription):
(WebCore::MockLibWebRTCPeerConnectionFactory::MockLibWebRTCPeerConnectionFactory):
(WebCore::MockLibWebRTCPeerConnectionFactory::CreatePeerConnection):
(WebCore::MockLibWebRTCPeerConnectionFactory::CreateLocalMediaStream):
(WebCore::MockLibWebRTCPeerConnection::SetLocalDescription):
(WebCore::MockLibWebRTCPeerConnection::SetRemoteDescription):
(WebCore::MockLibWebRTCPeerConnection::CreateDataChannel):
(WebCore::MockLibWebRTCPeerConnection::AddStream):
(WebCore::MockLibWebRTCPeerConnection::RemoveStream):
(WebCore::MockLibWebRTCPeerConnection::CreateOffer):
(WebCore::MockLibWebRTCPeerConnection::CreateAnswer):
* testing/MockLibWebRTCPeerConnection.h: Added.
(WebCore::MockLibWebRTCPeerConnection::~MockLibWebRTCPeerConnection):
(WebCore::MockLibWebRTCPeerConnection::MockLibWebRTCPeerConnection):
(WebCore::MockLibWebRTCPeerConnection::local_streams):
(WebCore::MockLibWebRTCPeerConnection::remote_streams):
(WebCore::MockLibWebRTCPeerConnection::CreateDtmfSender):
(WebCore::MockLibWebRTCPeerConnection::GetStats):
(WebCore::MockLibWebRTCPeerConnection::local_description):
(WebCore::MockLibWebRTCPeerConnection::remote_description):
(WebCore::MockLibWebRTCPeerConnection::AddIceCandidate):
(WebCore::MockLibWebRTCPeerConnection::RegisterUMAObserver):
(WebCore::MockLibWebRTCPeerConnection::signaling_state):
(WebCore::MockLibWebRTCPeerConnection::ice_connection_state):
(WebCore::MockLibWebRTCPeerConnection::ice_gathering_state):
(WebCore::MockLibWebRTCPeerConnection::StopRtcEventLog):
(WebCore::MockLibWebRTCPeerConnection::Close):
(WebCore::MockLibWebRTCPeerConnection::gotLocalDescription):
(WebCore::MockLibWebRTCIceCandidate::MockLibWebRTCIceCandidate):
(WebCore::MockLibWebRTCAudioTrack::MockLibWebRTCAudioTrack):
(WebCore::MockLibWebRTCVideoTrack::MockLibWebRTCVideoTrack):
(WebCore::MockLibWebRTCDataChannel::MockLibWebRTCDataChannel):
(WebCore::MockLibWebRTCPeerConnectionFactory::create):

LayoutTests:

* TestExpectations: Marking webrtc new tests as skipped for the moment.
* fast/mediastream/RTCPeerConnection-createAnswer.html:
* fast/mediastream/RTCPeerConnection-icecandidate-event.html:
* fast/mediastream/RTCPeerConnection-iceconnectionstatechange-event.html:
* webrtc/datachannel/basic.html: Added.
* webrtc/routines.js: Added.
(createConnections):
(closeConnections):
(onCreateSessionDescriptionError):
(gotDescription1):
(gotDescription2):
(iceCallback1):
(iceCallback2):
(onAddIceCandidateSuccess):
(onAddIceCandidateError):
* webrtc/video.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsTestExpectations">trunk/LayoutTests/TestExpectations</a></li>
<li><a href="#trunkLayoutTestsfastmediastreamRTCPeerConnectioncreateAnswerhtml">trunk/LayoutTests/fast/mediastream/RTCPeerConnection-createAnswer.html</a></li>
<li><a href="#trunkLayoutTestsfastmediastreamRTCPeerConnectionicecandidateeventhtml">trunk/LayoutTests/fast/mediastream/RTCPeerConnection-icecandidate-event.html</a></li>
<li><a href="#trunkLayoutTestsfastmediastreamRTCPeerConnectioniceconnectionstatechangeeventhtml">trunk/LayoutTests/fast/mediastream/RTCPeerConnection-iceconnectionstatechange-event.html</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamlibwebrtcLibWebRTCUtilscpp">trunk/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCUtils.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamlibwebrtcLibWebRTCUtilsh">trunk/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCUtils.h</a></li>
<li><a href="#trunkSourceWebCoretestingInternalscpp">trunk/Source/WebCore/testing/Internals.cpp</a></li>
<li><a href="#trunkSourceWebCoretestingInternalsh">trunk/Source/WebCore/testing/Internals.h</a></li>
<li><a href="#trunkSourceWebCoretestingInternalsidl">trunk/Source/WebCore/testing/Internals.idl</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastmediastreamgetUserMediawebaudioexpectedtxt">trunk/LayoutTests/fast/mediastream/getUserMedia-webaudio-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastmediastreamgetUserMediawebaudiohtml">trunk/LayoutTests/fast/mediastream/getUserMedia-webaudio.html</a></li>
<li>trunk/LayoutTests/webrtc/</li>
<li>trunk/LayoutTests/webrtc/datachannel/</li>
<li><a href="#trunkLayoutTestswebrtcdatachannelbasichtml">trunk/LayoutTests/webrtc/datachannel/basic.html</a></li>
<li><a href="#trunkLayoutTestswebrtcroutinesjs">trunk/LayoutTests/webrtc/routines.js</a></li>
<li><a href="#trunkLayoutTestswebrtcvideohtml">trunk/LayoutTests/webrtc/video.html</a></li>
<li><a href="#trunkSourceWebCoretestingMockLibWebRTCPeerConnectioncpp">trunk/Source/WebCore/testing/MockLibWebRTCPeerConnection.cpp</a></li>
<li><a href="#trunkSourceWebCoretestingMockLibWebRTCPeerConnectionh">trunk/Source/WebCore/testing/MockLibWebRTCPeerConnection.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (211252 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2017-01-27 04:29:16 UTC (rev 211252)
+++ trunk/LayoutTests/ChangeLog        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -1,3 +1,27 @@
</span><ins>+2017-01-26  Youenn Fablet  &lt;youennf@gmail.com&gt;
+
+        [WebRTC] Add a LibWebRTC mock for testing
+        https://bugs.webkit.org/show_bug.cgi?id=167429
+
+        Reviewed by Alex Christensen.
+
+        * TestExpectations: Marking webrtc new tests as skipped for the moment.
+        * fast/mediastream/RTCPeerConnection-createAnswer.html:
+        * fast/mediastream/RTCPeerConnection-icecandidate-event.html:
+        * fast/mediastream/RTCPeerConnection-iceconnectionstatechange-event.html:
+        * webrtc/datachannel/basic.html: Added.
+        * webrtc/routines.js: Added.
+        (createConnections):
+        (closeConnections):
+        (onCreateSessionDescriptionError):
+        (gotDescription1):
+        (gotDescription2):
+        (iceCallback1):
+        (iceCallback2):
+        (onAddIceCandidateSuccess):
+        (onAddIceCandidateError):
+        * webrtc/video.html: Added.
+
</ins><span class="cx"> 2017-01-26  Daniel Bates  &lt;dabates@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [QuickLook] Add test to ensure that RTF documents have a unique origin
</span></span></pre></div>
<a id="trunkLayoutTestsTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/TestExpectations (211252 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/TestExpectations        2017-01-27 04:29:16 UTC (rev 211252)
+++ trunk/LayoutTests/TestExpectations        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -679,6 +679,9 @@
</span><span class="cx"> # Media Sessions is not yet enabled by default: ENABLE(MEDIA_SESSION)
</span><span class="cx"> media/session [ Skip ]
</span><span class="cx"> 
</span><ins>+# WebRTC backend not enabled by default.
+webrtc [ Skip ]
+
</ins><span class="cx"> # Only iOS WK1 has testRunner.setPagePaused.
</span><span class="cx"> fast/dom/timer-fire-after-page-pause.html [ Skip ]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamRTCPeerConnectioncreateAnswerhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/mediastream/RTCPeerConnection-createAnswer.html (211252 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/RTCPeerConnection-createAnswer.html        2017-01-27 04:29:16 UTC (rev 211252)
+++ trunk/LayoutTests/fast/mediastream/RTCPeerConnection-createAnswer.html        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -67,13 +67,13 @@
</span><span class="cx">             {
</span><span class="cx">                 testPassed('createAnswer request succeeded.');
</span><span class="cx"> 
</span><del>-                sessionDescription = new RTCSessionDescription({type:&quot;offer&quot;, sdp:&quot;remote&quot;});
</del><ins>+                sessionDescription = new RTCSessionDescription({type:&quot;offer&quot;, sdp:&quot;v=0\r\no=- 5667094644266930845 0 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n&quot;});
</ins><span class="cx">                 shouldNotThrow('pc.setRemoteDescription(sessionDescription, setDescriptionSucceeded, setDescriptionFailed);');
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            function setDescriptionFailed()
</del><ins>+            function setDescriptionFailed(message)
</ins><span class="cx">             {
</span><del>-                testFailed('setRemoteDescription failed.');
</del><ins>+                testFailed('setRemoteDescription failed: ' + message);
</ins><span class="cx"> 
</span><span class="cx">                 finishJSTest();
</span><span class="cx">             }
</span><span class="lines">@@ -81,7 +81,7 @@
</span><span class="cx">             function setDescriptionSucceeded()
</span><span class="cx">             {
</span><span class="cx">                 testPassed('setRemoteDescription succeeded.');
</span><del>-                shouldThrow('pc.createAnswer(requestSucceeded2, requestFailed2, {});');
</del><ins>+                pc.createAnswer(requestSucceeded2, requestFailed2, {});
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             pc = new RTCPeerConnection({iceServers:[{urls:'stun:foo.com'}]});
</span></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamRTCPeerConnectionicecandidateeventhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/mediastream/RTCPeerConnection-icecandidate-event.html (211252 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/RTCPeerConnection-icecandidate-event.html        2017-01-27 04:29:16 UTC (rev 211252)
+++ trunk/LayoutTests/fast/mediastream/RTCPeerConnection-icecandidate-event.html        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -10,6 +10,9 @@
</span><span class="cx"> 
</span><span class="cx">             description(&quot;Test RTCPeerConnection 'icecandidate' event and gathering done&quot;);
</span><span class="cx"> 
</span><ins>+            if (window.internals)
+                internals.useMockRTCPeerConnectionFactory(&quot;ICECandidates&quot;);
+
</ins><span class="cx">             if (window.testRunner)
</span><span class="cx">                 testRunner.setUserMediaPermission(true);
</span><span class="cx">             else {
</span></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamRTCPeerConnectioniceconnectionstatechangeeventhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/mediastream/RTCPeerConnection-iceconnectionstatechange-event.html (211252 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/RTCPeerConnection-iceconnectionstatechange-event.html        2017-01-27 04:29:16 UTC (rev 211252)
+++ trunk/LayoutTests/fast/mediastream/RTCPeerConnection-iceconnectionstatechange-event.html        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -8,6 +8,9 @@
</span><span class="cx">         &lt;script&gt;
</span><span class="cx">             description(&quot;Test RTCPeerConnection 'iceconnectionstatechange' event&quot;);
</span><span class="cx"> 
</span><ins>+            if (window.internals)
+                internals.useMockRTCPeerConnectionFactory(&quot;ICEConnectionState&quot;);
+
</ins><span class="cx">             let expectedState;
</span><span class="cx">             let expectedStates = [
</span><span class="cx">                 &quot;checking&quot;,
</span></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamgetUserMediawebaudioexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/mediastream/getUserMedia-webaudio-expected.txt (0 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/getUserMedia-webaudio-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/mediastream/getUserMedia-webaudio-expected.txt        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -0,0 +1,3 @@
</span><ins>+
+PASS Plugging in getUserMedia audio stream into Web Audio 
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamgetUserMediawebaudiohtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/mediastream/getUserMedia-webaudio.html (0 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/getUserMedia-webaudio.html                                (rev 0)
+++ trunk/LayoutTests/fast/mediastream/getUserMedia-webaudio.html        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -0,0 +1,47 @@
</span><ins>+&lt;!doctype html&gt;
+&lt;html&gt;
+    &lt;head&gt;
+        &lt;meta charset=&quot;utf-8&quot;&gt;
+        &lt;title&gt;Testing getUserMedia plugged in Web Audio&lt;/title&gt;
+        &lt;script src=&quot;../../resources/testharness.js&quot;&gt;&lt;/script&gt;
+        &lt;script src=&quot;../../resources/testharnessreport.js&quot;&gt;&lt;/script&gt;
+    &lt;/head&gt;
+    &lt;body&gt;
+        &lt;script&gt;
+if (window.testRunner)
+    testRunner.setUserMediaPermission(true);
+
+var finishTest, errorTest;
+promise_test((test) =&gt; {
+    return navigator.mediaDevices.getUserMedia({ audio: true}).then((stream) =&gt; {
+        return new Promise((resolve, reject) =&gt; {
+            finishTest = resolve;
+            errorTest = reject;
+            var audioContext = new webkitAudioContext();
+            var script = audioContext.createScriptProcessor(2048, 1, 1);
+            script.onaudioprocess = (event) =&gt; {
+                var sum = 0.0;
+                var squaredSum = 0.0;
+                event.inputBuffer.getChannelData(0).forEach((value) =&gt; {
+                    sum += value;
+                    squaredSum += value * value;
+                });
+                if (Math.abs(sum) &gt; 5)
+                    errorTest(&quot;sum is not below 1&quot;);
+                // Mock source should send some bips with sufficient energy to finish the test
+                if (squaredSum &gt; 30) {
+                    source.disconnect(script);
+                    script.disconnect(audioContext.destination);
+                    finishTest();
+                }
+            };
+            let source = audioContext.createMediaStreamSource(stream);
+
+            source.connect(script);
+            script.connect(audioContext.destination);
+        });
+    });
+}, &quot;Plugging in getUserMedia audio stream into Web Audio&quot;);
+        &lt;/script&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestswebrtcdatachannelbasichtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/webrtc/datachannel/basic.html (0 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/webrtc/datachannel/basic.html                                (rev 0)
+++ trunk/LayoutTests/webrtc/datachannel/basic.html        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -0,0 +1,93 @@
</span><ins>+&lt;!doctype html&gt;
+&lt;html&gt;
+  &lt;head&gt;
+    &lt;meta charset=&quot;utf-8&quot;&gt;
+    &lt;title&gt;Testing basic data channel from offerer to receiver&lt;/title&gt;
+    &lt;script src=&quot;../../resources/testharness.js&quot;&gt;&lt;/script&gt;
+    &lt;script src=&quot;../../resources/testharnessreport.js&quot;&gt;&lt;/script&gt;
+  &lt;/head&gt;
+  &lt;body&gt;
+    &lt;script src =&quot;../routines.js&quot;&gt;&lt;/script&gt;
+    &lt;script&gt;
+if (window.internals)
+    internals.useMockRTCPeerConnectionFactory(&quot;TwoRealPeerConnections&quot;);
+
+var localChannel;
+var remoteChannel;
+
+function startTest() {
+    createConnections((localConnection) =&gt; {
+        localChannel = localConnection.createDataChannel('sendDataChannel');
+        localChannel.onopen = () =&gt; { sendMessages(localChannel) };
+    }, (remoteConnection) =&gt; {
+        remoteConnection.ondatachannel = (event) =&gt; {
+            remoteChannel = event.channel;
+            remoteChannel.onmessage = receiveMessages;
+        };
+    });
+}
+
+function closeDataChannels() {
+    localChannel.close();
+    remoteChannel.close();
+    closeConnections();
+}
+
+function receiveMessages(event) {
+    if (++counter === 1)
+        assert_equals(event.data, &quot;one&quot;);
+    else if (counter === 2)
+        assert_equals(event.data, &quot;two&quot;);
+    else if (counter === 3)
+        assert_equals(event.data, &quot;three&quot;);
+    else if (counter === 4) {
+        assert_equals(event.data, &quot;four&quot;);
+        closeDataChannels();
+        finishTest();
+    } else
+        assert_unreached();
+}
+
+function sendMessages(channel)
+{
+    channel.send(&quot;one&quot;);
+    channel.send(&quot;two&quot;);
+    channel.send(&quot;three&quot;);
+    channel.send(&quot;four&quot;);
+}
+
+var finishTest;
+promise_test((test) =&gt; {
+    counter = 0;
+    return new Promise((resolve, reject) =&gt; {
+        finishTest = resolve;
+        createConnections((localConnection) =&gt; {
+            localChannel = localConnection.createDataChannel('sendDataChannel');
+            localChannel.onopen = () =&gt; { sendMessages(localChannel) };
+        }, (remoteConnection) =&gt; {
+            remoteConnection.ondatachannel = (event) =&gt; {
+                remoteChannel = event.channel;
+                remoteChannel.onmessage = receiveMessages;
+            };
+        });
+    });
+}, &quot;Basic data channel exchange from offerer to receiver&quot;);
+
+promise_test((test) =&gt; {
+    counter = 0;
+    return new Promise((resolve, reject) =&gt; {
+        finishTest = resolve;
+        createConnections((localConnection) =&gt; {
+            localChannel = localConnection.createDataChannel('sendDataChannel');
+            localChannel.onmessage = receiveMessages;
+        }, (remoteConnection) =&gt; {
+            remoteConnection.ondatachannel = (event) =&gt; {
+                remoteChannel = event.channel;
+                remoteChannel.onopen = () =&gt; { sendMessages(remoteChannel) };
+            };
+        });
+    });
+}, &quot;Basic data channel exchange from receiver to offerer&quot;);
+    &lt;/script&gt;
+  &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestswebrtcroutinesjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/webrtc/routines.js (0 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/webrtc/routines.js                                (rev 0)
+++ trunk/LayoutTests/webrtc/routines.js        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -0,0 +1,62 @@
</span><ins>+// Test inspired from https://webrtc.github.io/samples/
+var localConnection;
+var remoteConnection;
+
+function createConnections(setupLocalConnection, setupRemoteConnection) {
+    localConnection = new RTCPeerConnection();
+    localConnection.onicecandidate = iceCallback1;
+    setupLocalConnection(localConnection);
+
+    remoteConnection = new RTCPeerConnection();
+    remoteConnection.onicecandidate = iceCallback2;
+    setupRemoteConnection(remoteConnection);
+
+    localConnection.createOffer().then(gotDescription1, onCreateSessionDescriptionError);
+
+    return [localConnection, remoteConnection]
+}
+
+function closeConnections()
+{
+    localConnection.close();
+    remoteConnection.close();
+}
+
+function onCreateSessionDescriptionError(error)
+{
+    assert_unreached();
+}
+
+function gotDescription1(desc)
+{
+    localConnection.setLocalDescription(desc);
+    remoteConnection.setRemoteDescription(desc);
+    remoteConnection.createAnswer().then(gotDescription2, onCreateSessionDescriptionError);
+}
+
+function gotDescription2(desc)
+{
+    remoteConnection.setLocalDescription(desc);
+    localConnection.setRemoteDescription(desc);
+}
+
+function iceCallback1(event)
+{
+    if (event.candidate)
+        remoteConnection.addIceCandidate(event.candidate).then(onAddIceCandidateSuccess, onAddIceCandidateError);
+}
+
+function iceCallback2(event)
+{
+    if (event.candidate)
+        localConnection.addIceCandidate(event.candidate).then(onAddIceCandidateSuccess, onAddIceCandidateError);
+}
+
+function onAddIceCandidateSuccess()
+{
+}
+
+function onAddIceCandidateError(error)
+{
+    assert_unreached();
+}
</ins></span></pre></div>
<a id="trunkLayoutTestswebrtcvideohtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/webrtc/video.html (0 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/webrtc/video.html                                (rev 0)
+++ trunk/LayoutTests/webrtc/video.html        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -0,0 +1,80 @@
</span><ins>+&lt;!doctype html&gt;
+&lt;html&gt;
+    &lt;head&gt;
+        &lt;meta charset=&quot;utf-8&quot;&gt;
+        &lt;title&gt;Testing basic data channel from offerer to receiver&lt;/title&gt;
+        &lt;script src=&quot;../resources/testharness.js&quot;&gt;&lt;/script&gt;
+        &lt;script src=&quot;../resources/testharnessreport.js&quot;&gt;&lt;/script&gt;
+    &lt;/head&gt;
+    &lt;body&gt;
+        &lt;video id=&quot;video&quot; autoplay=&quot;&quot;&gt;&lt;/video&gt;
+        &lt;canvas id=&quot;canvas&quot; width=&quot;640&quot; height=&quot;480&quot;&gt;&lt;/canvas&gt;
+        &lt;script src =&quot;routines.js&quot;&gt;&lt;/script&gt;
+        &lt;script&gt;
+if (window.internals)
+    internals.useMockRTCPeerConnectionFactory(&quot;TwoRealPeerConnections&quot;);
+
+if (window.testRunner)
+    testRunner.setUserMediaPermission(true);
+
+video = document.getElementById(&quot;video&quot;);
+canvas = document.getElementById(&quot;canvas&quot;);
+// FIXME: We should use tracks
+
+function testImage()
+{
+    try {
+        canvas.width = video.videoWidth;
+        canvas.height = video.videoHeight;
+        canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
+
+        imageData = canvas.getContext('2d').getImageData(10, 325, 250, 1);
+        data = imageData.data;
+
+        var index = 20;
+        assert_true(data[index] &lt; 100);
+        assert_true(data[index + 1] &lt; 100);
+        assert_true(data[index + 2] &lt; 100);
+
+        index = 80;
+        assert_true(data[index] &gt; 200);
+        assert_true(data[index + 1] &gt; 200);
+        assert_true(data[index + 2] &gt; 200);
+
+        index += 80;
+        assert_true(data[index] &gt; 200);
+        assert_true(data[index + 1] &gt; 200);
+        assert_true(data[index + 2] &lt; 100);
+
+        finishTest();
+    } catch(e) {
+        errorTest(e);
+    }
+}
+
+function testStream(stream)
+{
+    video.srcObject = stream;
+    // Video may play with black frames
+    video.onplay = setTimeout(() =&gt; {
+        testImage();
+    }, 1000);
+}
+
+var finishTest, errorTest;
+promise_test((test) =&gt; {
+    return navigator.mediaDevices.getUserMedia({ video: true}).then((stream) =&gt; {
+        return new Promise((resolve, reject) =&gt; {
+            finishTest = resolve;
+            errorTest = reject;
+            createConnections((firstConnection) =&gt; {
+                firstConnection.addStream(stream);
+            }, (secondConnection) =&gt; {
+                secondConnection.onaddstream = (streamEvent) =&gt; { testStream(streamEvent.stream); };
+            });
+        });
+    });
+}, &quot;Basic video exchange&quot;);
+        &lt;/script&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (211252 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-01-27 04:29:16 UTC (rev 211252)
+++ trunk/Source/WebCore/ChangeLog        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -1,3 +1,64 @@
</span><ins>+2017-01-26  Youenn Fablet  &lt;youennf@gmail.com&gt;
+
+        [WebRTC] Add a LibWebRTC mock for testing
+        https://bugs.webkit.org/show_bug.cgi?id=167429
+
+        Reviewed by Alex Christensen.
+
+        Covered by updated tests although feature is behind a flag, off by default.
+        MockLibWebRTCPeerConnection will allow us testing the code above the WebRTC implementation above LibWebRTC,
+        without reyling on it and controlling the way that the peer connections will behave.
+        Adding support for mock factory to create real peer connections in case where we want to do full testing through the local loopback.
+
+        Tests: fast/mediastream/getUserMedia-webaudio.html
+               webrtc/datachannel/basic.html
+               webrtc/video.html
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * testing/Internals.cpp:
+        (WebCore::Internals::Internals):
+        (WebCore::Internals::useMockRTCPeerConnectionFactory):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+        * testing/MockLibWebRTCPeerConnection.cpp: Added.
+        (WebCore::useMockRTCPeerConnectionFactory):
+        (WebCore::MockLibWebRTCPeerConnectionForIceCandidates::MockLibWebRTCPeerConnectionForIceCandidates):
+        (WebCore::MockLibWebRTCPeerConnectionForIceCandidates::gotLocalDescription):
+        (WebCore::MockLibWebRTCPeerConnectionForIceConnectionState::MockLibWebRTCPeerConnectionForIceConnectionState):
+        (WebCore::MockLibWebRTCPeerConnectionForIceConnectionState::gotLocalDescription):
+        (WebCore::MockLibWebRTCPeerConnectionFactory::MockLibWebRTCPeerConnectionFactory):
+        (WebCore::MockLibWebRTCPeerConnectionFactory::CreatePeerConnection):
+        (WebCore::MockLibWebRTCPeerConnectionFactory::CreateLocalMediaStream):
+        (WebCore::MockLibWebRTCPeerConnection::SetLocalDescription):
+        (WebCore::MockLibWebRTCPeerConnection::SetRemoteDescription):
+        (WebCore::MockLibWebRTCPeerConnection::CreateDataChannel):
+        (WebCore::MockLibWebRTCPeerConnection::AddStream):
+        (WebCore::MockLibWebRTCPeerConnection::RemoveStream):
+        (WebCore::MockLibWebRTCPeerConnection::CreateOffer):
+        (WebCore::MockLibWebRTCPeerConnection::CreateAnswer):
+        * testing/MockLibWebRTCPeerConnection.h: Added.
+        (WebCore::MockLibWebRTCPeerConnection::~MockLibWebRTCPeerConnection):
+        (WebCore::MockLibWebRTCPeerConnection::MockLibWebRTCPeerConnection):
+        (WebCore::MockLibWebRTCPeerConnection::local_streams):
+        (WebCore::MockLibWebRTCPeerConnection::remote_streams):
+        (WebCore::MockLibWebRTCPeerConnection::CreateDtmfSender):
+        (WebCore::MockLibWebRTCPeerConnection::GetStats):
+        (WebCore::MockLibWebRTCPeerConnection::local_description):
+        (WebCore::MockLibWebRTCPeerConnection::remote_description):
+        (WebCore::MockLibWebRTCPeerConnection::AddIceCandidate):
+        (WebCore::MockLibWebRTCPeerConnection::RegisterUMAObserver):
+        (WebCore::MockLibWebRTCPeerConnection::signaling_state):
+        (WebCore::MockLibWebRTCPeerConnection::ice_connection_state):
+        (WebCore::MockLibWebRTCPeerConnection::ice_gathering_state):
+        (WebCore::MockLibWebRTCPeerConnection::StopRtcEventLog):
+        (WebCore::MockLibWebRTCPeerConnection::Close):
+        (WebCore::MockLibWebRTCPeerConnection::gotLocalDescription):
+        (WebCore::MockLibWebRTCIceCandidate::MockLibWebRTCIceCandidate):
+        (WebCore::MockLibWebRTCAudioTrack::MockLibWebRTCAudioTrack):
+        (WebCore::MockLibWebRTCVideoTrack::MockLibWebRTCVideoTrack):
+        (WebCore::MockLibWebRTCDataChannel::MockLibWebRTCDataChannel):
+        (WebCore::MockLibWebRTCPeerConnectionFactory::create):
+
</ins><span class="cx"> 2017-01-26  Jeremy Jones  &lt;jeremyj@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Page should be able to request pointer lock without user gesture if it relinquished it without a user gesture
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (211252 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2017-01-27 04:29:16 UTC (rev 211252)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -1544,6 +1544,8 @@
</span><span class="cx">                 4157474A1E3869AD00E914D8 /* LibWebRTCUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 415747461E38699E00E914D8 /* LibWebRTCUtils.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 4157AF8012F1FB0400A8C6F5 /* MediaControlsApple.h in Headers */ = {isa = PBXBuildFile; fileRef = 4157AF7E12F1FB0400A8C6F5 /* MediaControlsApple.h */; };
</span><span class="cx">                 4157AF8112F1FB0400A8C6F5 /* MediaControlsApple.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4157AF7F12F1FB0400A8C6F5 /* MediaControlsApple.cpp */; };
</span><ins>+                4157EBFA1E3AB67900AC9FE9 /* MockLibWebRTCPeerConnection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4157EBF91E3AB06800AC9FE9 /* MockLibWebRTCPeerConnection.cpp */; };
+                4157EBFB1E3AB67F00AC9FE9 /* MockLibWebRTCPeerConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4157EBF81E3AB06800AC9FE9 /* MockLibWebRTCPeerConnection.h */; };
</ins><span class="cx">                 41614A781DA6423B004AD06F /* HTTPHeaderValues.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41614A761DA64236004AD06F /* HTTPHeaderValues.cpp */; };
</span><span class="cx">                 41614A791DA64241004AD06F /* HTTPHeaderValues.h in Headers */ = {isa = PBXBuildFile; fileRef = 41614A771DA64236004AD06F /* HTTPHeaderValues.h */; };
</span><span class="cx">                 4162A450101145AE00DFF3ED /* DedicatedWorkerGlobalScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4162A44D101145AE00DFF3ED /* DedicatedWorkerGlobalScope.cpp */; };
</span><span class="lines">@@ -8725,6 +8727,8 @@
</span><span class="cx">                 415747461E38699E00E914D8 /* LibWebRTCUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LibWebRTCUtils.h; path = libwebrtc/LibWebRTCUtils.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 4157AF7E12F1FB0400A8C6F5 /* MediaControlsApple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaControlsApple.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 4157AF7F12F1FB0400A8C6F5 /* MediaControlsApple.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaControlsApple.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                4157EBF81E3AB06800AC9FE9 /* MockLibWebRTCPeerConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockLibWebRTCPeerConnection.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                4157EBF91E3AB06800AC9FE9 /* MockLibWebRTCPeerConnection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MockLibWebRTCPeerConnection.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 41614A761DA64236004AD06F /* HTTPHeaderValues.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPHeaderValues.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 41614A771DA64236004AD06F /* HTTPHeaderValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPHeaderValues.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 4162A44D101145AE00DFF3ED /* DedicatedWorkerGlobalScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DedicatedWorkerGlobalScope.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -16693,6 +16697,8 @@
</span><span class="cx">                                 51058AD81D679257009A538C /* MockGamepad.h */,
</span><span class="cx">                                 51058AD91D679257009A538C /* MockGamepadProvider.cpp */,
</span><span class="cx">                                 51058ADA1D679257009A538C /* MockGamepadProvider.h */,
</span><ins>+                                4157EBF81E3AB06800AC9FE9 /* MockLibWebRTCPeerConnection.h */,
+                                4157EBF91E3AB06800AC9FE9 /* MockLibWebRTCPeerConnection.cpp */,
</ins><span class="cx">                                 2D6F3E8A1C1ECB1C0061DBD4 /* MockPageOverlay.cpp */,
</span><span class="cx">                                 2D6F3E8B1C1ECB1C0061DBD4 /* MockPageOverlay.h */,
</span><span class="cx">                                 2D6F3E8C1C1ECB1C0061DBD4 /* MockPageOverlay.idl */,
</span><span class="lines">@@ -24911,6 +24917,7 @@
</span><span class="cx">                                 AA5F3B8D16CC33D100455EB0 /* PlatformSpeechSynthesizerMock.h in Headers */,
</span><span class="cx">                                 A1763F3F1E205234001D58DE /* WebArchiveDumpSupport.h in Headers */,
</span><span class="cx">                                 41815C1F138319830057AAA4 /* WebCoreTestSupport.h in Headers */,
</span><ins>+                                4157EBFB1E3AB67F00AC9FE9 /* MockLibWebRTCPeerConnection.h in Headers */,
</ins><span class="cx">                         );
</span><span class="cx">                         runOnlyForDeploymentPostprocessing = 0;
</span><span class="cx">                 };
</span><span class="lines">@@ -28834,6 +28841,7 @@
</span><span class="cx">                                 51714EB01CF665CE004723C4 /* JSGCObservation.cpp in Sources */,
</span><span class="cx">                                 417DA71D13735DFA007C57FB /* JSInternals.cpp in Sources */,
</span><span class="cx">                                 A740B5A714C935AF00A77FA4 /* JSInternalSettings.cpp in Sources */,
</span><ins>+                                4157EBFA1E3AB67900AC9FE9 /* MockLibWebRTCPeerConnection.cpp in Sources */,
</ins><span class="cx">                                 53ED3FDE167A88E7006762E6 /* JSInternalSettingsGenerated.cpp in Sources */,
</span><span class="cx">                                 A740B59714C935AF00A77FA4 /* JSMallocStatistics.cpp in Sources */,
</span><span class="cx">                                 CDF4B7331E03D14900E235A2 /* JSMediaKeysRequirement.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamlibwebrtcLibWebRTCUtilscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCUtils.cpp (211252 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCUtils.cpp        2017-01-27 04:29:16 UTC (rev 211252)
+++ trunk/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCUtils.cpp        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> 
</span><span class="cx"> #if USE(LIBWEBRTC)
</span><span class="cx"> 
</span><ins>+#include &lt;webrtc/api/peerconnectionfactoryproxy.h&gt;
</ins><span class="cx"> #include &lt;webrtc/api/peerconnectionfactory.h&gt;
</span><span class="cx"> #include &lt;webrtc/base/physicalsocketserver.h&gt;
</span><span class="cx"> #include &lt;webrtc/p2p/client/basicportallocator.h&gt;
</span><span class="lines">@@ -74,6 +75,12 @@
</span><span class="cx">     threads.networkThread-&gt;Post(RTC_FROM_HERE, &amp;threads, 1, new ThreadMessageData(WTFMove(callback)));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void callOnWebRTCSignalingThread(Function&lt;void()&gt;&amp;&amp; callback)
+{
+    PeerConnectionFactoryAndThreads&amp; threads = staticFactoryAndThreads();
+    threads.signalingThread-&gt;Post(RTC_FROM_HERE, &amp;threads, 1, new ThreadMessageData(WTFMove(callback)));
+}
+
</ins><span class="cx"> static void initializePeerConnectionFactoryAndThreads()
</span><span class="cx"> {
</span><span class="cx">     auto&amp; factoryAndThreads = staticFactoryAndThreads();
</span><span class="lines">@@ -106,6 +113,14 @@
</span><span class="cx">     return *staticFactoryAndThreads().factory;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void setPeerConnectionFactory(rtc::scoped_refptr&lt;webrtc::PeerConnectionFactoryInterface&gt;&amp;&amp; factory)
+{
+    if (!staticFactoryAndThreads().factory)
+        initializePeerConnectionFactoryAndThreads();
+
+    staticFactoryAndThreads().factory = webrtc::PeerConnectionFactoryProxy::Create(staticFactoryAndThreads().signalingThread.get(), WTFMove(factory));
+}
+
</ins><span class="cx"> static rtc::scoped_refptr&lt;webrtc::PeerConnectionInterface&gt; createPeerConnection(webrtc::PeerConnectionObserver&amp; observer, std::unique_ptr&lt;cricket::BasicPortAllocator&gt;&amp;&amp; portAllocator)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(staticFactoryAndThreads().factory);
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamlibwebrtcLibWebRTCUtilsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCUtils.h (211252 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCUtils.h        2017-01-27 04:29:16 UTC (rev 211252)
+++ trunk/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCUtils.h        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -52,6 +52,10 @@
</span><span class="cx"> 
</span><span class="cx"> WEBCORE_EXPORT void callOnWebRTCNetworkThread(Function&lt;void()&gt;&amp;&amp;);
</span><span class="cx"> 
</span><ins>+// Used for mock testing
+WEBCORE_EXPORT void setPeerConnectionFactory(rtc::scoped_refptr&lt;webrtc::PeerConnectionFactoryInterface&gt;&amp;&amp;);
+WEBCORE_EXPORT void callOnWebRTCSignalingThread(Function&lt;void()&gt;&amp;&amp;);
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif // USE(LIBWEBRTC)
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.cpp (211252 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.cpp        2017-01-27 04:29:16 UTC (rev 211252)
+++ trunk/Source/WebCore/testing/Internals.cpp        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -85,6 +85,8 @@
</span><span class="cx"> #include &quot;IntRect.h&quot;
</span><span class="cx"> #include &quot;InternalSettings.h&quot;
</span><span class="cx"> #include &quot;Language.h&quot;
</span><ins>+#include &quot;LibWebRTCProvider.h&quot;
+#include &quot;LibWebRTCUtils.h&quot;
</ins><span class="cx"> #include &quot;MainFrame.h&quot;
</span><span class="cx"> #include &quot;MallocStatistics.h&quot;
</span><span class="cx"> #include &quot;MediaPlayer.h&quot;
</span><span class="lines">@@ -92,6 +94,7 @@
</span><span class="cx"> #include &quot;MemoryCache.h&quot;
</span><span class="cx"> #include &quot;MemoryInfo.h&quot;
</span><span class="cx"> #include &quot;MemoryPressureHandler.h&quot;
</span><ins>+#include &quot;MockLibWebRTCPeerConnection.h&quot;
</ins><span class="cx"> #include &quot;MockPageOverlay.h&quot;
</span><span class="cx"> #include &quot;MockPageOverlayClient.h&quot;
</span><span class="cx"> #include &quot;Page.h&quot;
</span><span class="lines">@@ -450,6 +453,7 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(WEB_RTC)
</span><span class="cx">     enableMockMediaEndpoint();
</span><ins>+    useMockRTCPeerConnectionFactory(String());
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(WIRELESS_PLAYBACK_TARGET)
</span><span class="lines">@@ -1091,8 +1095,19 @@
</span><span class="cx">     connection.emulatePlatformEvent(action);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Internals::useMockRTCPeerConnectionFactory(const String&amp; testCase)
+{
+#if USE(LIBWEBRTC)
+    Document* document = contextDocument();
+    LibWebRTCProvider* provider = (document &amp;&amp; document-&gt;page()) ? &amp;document-&gt;page()-&gt;libWebRTCProvider() : nullptr;
+    WebCore::useMockRTCPeerConnectionFactory(provider, testCase);
+#else
+    UNUSED_PARAM(testCase);
</ins><span class="cx"> #endif
</span><ins>+}
</ins><span class="cx"> 
</span><ins>+#endif
+
</ins><span class="cx"> #if ENABLE(MEDIA_STREAM)
</span><span class="cx"> 
</span><span class="cx"> void Internals::setMockMediaCaptureDevicesEnabled(bool enabled)
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.h (211252 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.h        2017-01-27 04:29:16 UTC (rev 211252)
+++ trunk/Source/WebCore/testing/Internals.h        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -390,6 +390,7 @@
</span><span class="cx">     void enableMockMediaEndpoint();
</span><span class="cx">     void enableMockRTCPeerConnectionHandler();
</span><span class="cx">     void emulateRTCPeerConnectionPlatformEvent(RTCPeerConnection&amp;, const String&amp; action);
</span><ins>+    void useMockRTCPeerConnectionFactory(const String&amp;);
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     String getImageSourceURL(Element&amp;);
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalsidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.idl (211252 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.idl        2017-01-27 04:29:16 UTC (rev 211252)
+++ trunk/Source/WebCore/testing/Internals.idl        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -435,6 +435,7 @@
</span><span class="cx">     [Conditional=WIRELESS_PLAYBACK_TARGET, MayThrowException] void setMockMediaPlaybackTargetPickerState(DOMString deviceName, DOMString deviceState);
</span><span class="cx">     [Conditional=MEDIA_STREAM] void setMockMediaCaptureDevicesEnabled(boolean enabled);
</span><span class="cx">     [Conditional=WEB_RTC] void emulateRTCPeerConnectionPlatformEvent(RTCPeerConnection connection, DOMString action);
</span><ins>+    [Conditional=WEB_RTC] void useMockRTCPeerConnectionFactory(DOMString testCase);
</ins><span class="cx"> 
</span><span class="cx">     [Conditional=VIDEO] void simulateSystemSleep();
</span><span class="cx">     [Conditional=VIDEO] void simulateSystemWake();
</span></span></pre></div>
<a id="trunkSourceWebCoretestingMockLibWebRTCPeerConnectioncpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/testing/MockLibWebRTCPeerConnection.cpp (0 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/MockLibWebRTCPeerConnection.cpp                                (rev 0)
+++ trunk/Source/WebCore/testing/MockLibWebRTCPeerConnection.cpp        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -0,0 +1,324 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &quot;config.h&quot;
+#include &quot;MockLibWebRTCPeerConnection.h&quot;
+
+#if USE(LIBWEBRTC)
+
+#include &quot;LibWebRTCProvider.h&quot;
+#include &quot;LibWebRTCUtils.h&quot;
+#include &lt;sstream&gt;
+#include &lt;webrtc/api/mediastream.h&gt;
+#include &lt;wtf/Function.h&gt;
+
+namespace WebCore {
+
+void useMockRTCPeerConnectionFactory(LibWebRTCProvider* provider, const String&amp; testCase)
+{
+    setPeerConnectionFactory(MockLibWebRTCPeerConnectionFactory::create(provider, String(testCase)));
+}
+
+class MockLibWebRTCPeerConnectionForIceCandidates : public MockLibWebRTCPeerConnection {
+public:
+    explicit MockLibWebRTCPeerConnectionForIceCandidates(webrtc::PeerConnectionObserver&amp; observer) : MockLibWebRTCPeerConnection(observer) { }
+    virtual ~MockLibWebRTCPeerConnectionForIceCandidates() = default;
+private:
+    void gotLocalDescription() final;
+};
+
+void MockLibWebRTCPeerConnectionForIceCandidates::gotLocalDescription()
+{
+    // Let's gather candidates
+    callOnWebRTCSignalingThread([this]() {
+        MockLibWebRTCIceCandidate candidate(&quot;2013266431 1 udp 2013266432 192.168.0.100 38838 typ host generation 0&quot;, &quot;1&quot;);
+        m_observer.OnIceCandidate(&amp;candidate);
+    });
+    callOnWebRTCSignalingThread([this]() {
+        MockLibWebRTCIceCandidate candidate(&quot;1019216383 1 tcp 1019216384 192.168.0.100 9 typ host tcptype passive generation 0&quot;, &quot;1&quot;);
+        m_observer.OnIceCandidate(&amp;candidate);
+    });
+    callOnWebRTCSignalingThread([this]() {
+        MockLibWebRTCIceCandidate candidate(&quot;1677722111 1 tcp 1677722112 172.18.0.1 47989 typ srflx raddr 192.168.0.100 rport 47989 generation 0&quot;, &quot;1&quot;);
+        m_observer.OnIceCandidate(&amp;candidate);
+    });
+    callOnWebRTCSignalingThread([this]() {
+        m_observer.OnIceGatheringChange(webrtc::PeerConnectionInterface::kIceGatheringComplete);
+    });
+}
+
+
+class MockLibWebRTCPeerConnectionForIceConnectionState : public MockLibWebRTCPeerConnection {
+public:
+    explicit MockLibWebRTCPeerConnectionForIceConnectionState(webrtc::PeerConnectionObserver&amp; observer) : MockLibWebRTCPeerConnection(observer) { }
+    virtual ~MockLibWebRTCPeerConnectionForIceConnectionState() = default;
+
+private:
+    void gotLocalDescription() final;
+};
+
+void MockLibWebRTCPeerConnectionForIceConnectionState::gotLocalDescription()
+{
+    m_observer.OnIceConnectionChange(kIceConnectionChecking);
+    m_observer.OnIceConnectionChange(kIceConnectionConnected);
+    m_observer.OnIceConnectionChange(kIceConnectionCompleted);
+    m_observer.OnIceConnectionChange(kIceConnectionFailed);
+    m_observer.OnIceConnectionChange(kIceConnectionDisconnected);
+    m_observer.OnIceConnectionChange(kIceConnectionNew);
+}
+
+MockLibWebRTCPeerConnectionFactory::MockLibWebRTCPeerConnectionFactory(LibWebRTCProvider* provider, String&amp;&amp; testCase)
+    : m_provider(provider)
+    , m_testCase(WTFMove(testCase))
+{
+    if (m_testCase == &quot;TwoRealPeerConnections&quot; &amp;&amp; m_provider)
+        m_numberOfRealPeerConnections = 2;
+}
+
+rtc::scoped_refptr&lt;webrtc::PeerConnectionInterface&gt; MockLibWebRTCPeerConnectionFactory::CreatePeerConnection(const webrtc::PeerConnectionInterface::RTCConfiguration&amp;, std::unique_ptr&lt;cricket::PortAllocator&gt;, std::unique_ptr&lt;rtc::RTCCertificateGeneratorInterface&gt;, webrtc::PeerConnectionObserver* observer)
+{
+    if (m_numberOfRealPeerConnections) {
+        ASSERT(m_provider);
+        auto connection = m_provider-&gt;createPeerConnection(*observer);
+        if (!--m_numberOfRealPeerConnections)
+            m_provider = nullptr;
+        return connection;
+    }
+
+    if (m_testCase == &quot;ICECandidates&quot;)
+        return new rtc::RefCountedObject&lt;MockLibWebRTCPeerConnectionForIceCandidates&gt;(*observer);
+
+    if (m_testCase == &quot;ICEConnectionState&quot;)
+        return new rtc::RefCountedObject&lt;MockLibWebRTCPeerConnectionForIceConnectionState&gt;(*observer);
+
+    return new rtc::RefCountedObject&lt;MockLibWebRTCPeerConnection&gt;(*observer);
+}
+
+rtc::scoped_refptr&lt;webrtc::MediaStreamInterface&gt; MockLibWebRTCPeerConnectionFactory::CreateLocalMediaStream(const std::string&amp; label)
+{
+    return new rtc::RefCountedObject&lt;webrtc::MediaStream&gt;(label);
+}
+
+void MockLibWebRTCPeerConnection::SetLocalDescription(webrtc::SetSessionDescriptionObserver* observer, webrtc::SessionDescriptionInterface*)
+{
+    callOnWebRTCSignalingThread([this, observer] {
+        observer-&gt;OnSuccess();
+        gotLocalDescription();
+    });
+}
+
+void MockLibWebRTCPeerConnection::SetRemoteDescription(webrtc::SetSessionDescriptionObserver* observer, webrtc::SessionDescriptionInterface* sessionDescription)
+{
+    callOnWebRTCSignalingThread([observer] {
+        observer-&gt;OnSuccess();
+    });
+    ASSERT(sessionDescription);
+    if (sessionDescription-&gt;type() == &quot;offer&quot;) {
+        std::string sdp;
+        sessionDescription-&gt;ToString(&amp;sdp);
+
+        m_isInitiator = false;
+        m_isReceivingAudio = sdp.find(&quot;m=audio&quot;) != std::string::npos;
+        m_isReceivingVideo = sdp.find(&quot;m=video&quot;) != std::string::npos;
+    }
+}
+
+rtc::scoped_refptr&lt;webrtc::DataChannelInterface&gt; MockLibWebRTCPeerConnection::CreateDataChannel(const std::string&amp; label, const webrtc::DataChannelInit* init)
+{
+    webrtc::DataChannelInit parameters;
+    if (init)
+        parameters = *init;
+    return new rtc::RefCountedObject&lt;MockLibWebRTCDataChannel&gt;(std::string(label), parameters.ordered, parameters.reliable, parameters.id);
+}
+
+bool MockLibWebRTCPeerConnection::AddStream(webrtc::MediaStreamInterface* stream)
+{
+    m_stream = stream;
+    return true;
+}
+
+void MockLibWebRTCPeerConnection::RemoveStream(webrtc::MediaStreamInterface*)
+{
+    m_stream = nullptr;
+}
+
+void MockLibWebRTCPeerConnection::CreateOffer(webrtc::CreateSessionDescriptionObserver* observer, const webrtc::MediaConstraintsInterface*)
+{
+    callOnWebRTCSignalingThread([this, observer] {
+        std::ostringstream sdp;
+        sdp &lt;&lt;
+            &quot;v=0\r\n&quot;
+            &quot;o=- 5667094644266930845 &quot; &lt;&lt; m_counter++ &lt;&lt; &quot; IN IP4 127.0.0.1\r\n&quot;
+            &quot;s=-\r\n&quot;
+            &quot;t=0 0\r\n&quot;;
+        if (m_stream) {
+            unsigned partCounter = 1;
+            sdp &lt;&lt; &quot;a=msid-semantic:WMS &quot; &lt;&lt; m_stream-&gt;label() &lt;&lt; &quot;\r\n&quot;;
+            for (auto&amp; audioTrack : m_stream-&gt;GetAudioTracks()) {
+                sdp &lt;&lt;
+                    &quot;m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0\r\n&quot;
+                    &quot;c=IN IP4 0.0.0.0\r\n&quot;
+                    &quot;a=rtcp-mux\r\n&quot;
+                    &quot;a=sendrecv\r\n&quot;
+                    &quot;a=mid:part&quot; &lt;&lt; partCounter++ &lt;&lt; &quot;\r\n&quot;
+                    &quot;a=rtpmap:111 OPUS/48000/2\r\n&quot;
+                    &quot;a=rtpmap:8 PCMA/8000\r\n&quot;
+                    &quot;a=rtpmap:0 PCMU/8000\r\n&quot;
+                    &quot;a=ssrc:3409173717 cname:/chKzCS9K6KOgL0n\r\n&quot;
+                    &quot;a=msid:&quot; &lt;&lt; m_stream-&gt;label() &lt;&lt; &quot; &quot; &lt;&lt; audioTrack-&gt;id() &lt;&lt; &quot;\r\n&quot;
+                    &quot;a=ice-ufrag:e/B1\r\n&quot;
+                    &quot;a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n&quot;
+                    &quot;a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n&quot;
+                    &quot;a=setup:actpass\r\n&quot;;
+            }
+            for (auto&amp; videoTrack : m_stream-&gt;GetVideoTracks()) {
+                sdp &lt;&lt;
+                    &quot;m=video 9 UDP/TLS/RTP/SAVPF 103 100 120\r\n&quot;
+                    &quot;c=IN IP4 0.0.0.0\r\n&quot;
+                    &quot;a=rtcp-mux\r\n&quot;
+                    &quot;a=sendrecv\r\n&quot;
+                    &quot;a=mid:part&quot; &lt;&lt; partCounter++ &lt;&lt; &quot;\r\n&quot;
+                    &quot;a=rtpmap:103 H264/90000\r\n&quot;
+                    &quot;a=rtpmap:100 VP8/90000\r\n&quot;
+                    &quot;a=rtpmap:120 RTX/90000\r\n&quot;
+                    &quot;a=fmtp:103 packetization-mode=1\r\n&quot;
+                    &quot;a=fmtp:120 apt=100;rtx-time=200\r\n&quot;
+                    &quot;a=rtcp-fb:100 nack\r\n&quot;
+                    &quot;a=rtcp-fb:103 nack pli\r\n&quot;
+                    &quot;a=rtcp-fb:100 nack pli\r\n&quot;
+                    &quot;a=rtcp-fb:103 ccm fir\r\n&quot;
+                    &quot;a=rtcp-fb:100 ccm fir\r\n&quot;
+                    &quot;a=ssrc:3409173718 cname:/chKzCS9K6KOgL0n\r\n&quot;
+                    &quot;a=msid:&quot; &lt;&lt; m_stream-&gt;label() &lt;&lt; &quot; &quot; &lt;&lt; videoTrack-&gt;id() &lt;&lt; &quot;\r\n&quot;
+                    &quot;a=ice-ufrag:e/B1\r\n&quot;
+                    &quot;a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n&quot;
+                    &quot;a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n&quot;
+                    &quot;a=setup:actpass\r\n&quot;;
+            }
+        }
+        MockLibWebRTCSessionDescription description(sdp.str());
+        observer-&gt;OnSuccess(&amp;description);
+    });
+}
+
+void MockLibWebRTCPeerConnection::CreateAnswer(webrtc::CreateSessionDescriptionObserver* observer, const webrtc::MediaConstraintsInterface*)
+{
+    callOnWebRTCSignalingThread([this, observer] {
+        std::ostringstream sdp;
+        sdp &lt;&lt;
+            &quot;v=0\r\n&quot;
+            &quot;o=- 5667094644266930846 &quot; &lt;&lt; m_counter++ &lt;&lt; &quot; IN IP4 127.0.0.1\r\n&quot;
+            &quot;s=-\r\n&quot;
+            &quot;t=0 0\r\n&quot;;
+        if (m_stream) {
+            for (auto&amp; audioTrack : m_stream-&gt;GetAudioTracks()) {
+                ASSERT_UNUSED(audioTrack, !!audioTrack);
+                sdp &lt;&lt;
+                    &quot;m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0\r\n&quot;
+                    &quot;c=IN IP4 0.0.0.0\r\n&quot;
+                    &quot;a=rtcp-mux\r\n&quot;
+                    &quot;a=recvonly\r\n&quot;
+                    &quot;a=mid:part1\r\n&quot;
+                    &quot;a=rtpmap:111 OPUS/48000/2\r\n&quot;
+                    &quot;a=rtpmap:8 PCMA/8000\r\n&quot;
+                    &quot;a=rtpmap:0 PCMU/8000\r\n&quot;
+                    &quot;a=ssrc:3409173717 cname:/chKzCS9K6KOgL0m\r\n&quot;
+                    &quot;a=ice-ufrag:e/B1\r\n&quot;
+                    &quot;a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n&quot;
+                    &quot;a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n&quot;
+                    &quot;a=setup:active\r\n&quot;;
+            }
+            for (auto&amp; videoTrack : m_stream-&gt;GetVideoTracks()) {
+                ASSERT_UNUSED(videoTrack, !!videoTrack);
+                sdp &lt;&lt;
+                    &quot;m=video 9 UDP/TLS/RTP/SAVPF 103 100 120\r\n&quot;
+                    &quot;c=IN IP4 0.0.0.0\r\n&quot;
+                    &quot;a=rtcp-mux\r\n&quot;
+                    &quot;a=recvonly\r\n&quot;
+                    &quot;a=mid:part2\r\n&quot;
+                    &quot;a=rtpmap:103 H264/90000\r\n&quot;
+                    &quot;a=rtpmap:100 VP8/90000\r\n&quot;
+                    &quot;a=rtpmap:120 RTX/90000\r\n&quot;
+                    &quot;a=fmtp:103 packetization-mode=1\r\n&quot;
+                    &quot;a=fmtp:120 apt=100;rtx-time=200\r\n&quot;
+                    &quot;a=rtcp-fb:100 nack\r\n&quot;
+                    &quot;a=rtcp-fb:103 nack pli\r\n&quot;
+                    &quot;a=rtcp-fb:100 nack pli\r\n&quot;
+                    &quot;a=rtcp-fb:103 ccm fir\r\n&quot;
+                    &quot;a=rtcp-fb:100 ccm fir\r\n&quot;
+                    &quot;a=ssrc:3409173718 cname:/chKzCS9K6KOgL0n\r\n&quot;
+                    &quot;a=ice-ufrag:e/B1\r\n&quot;
+                    &quot;a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n&quot;
+                    &quot;a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n&quot;
+                    &quot;a=setup:active\r\n&quot;;
+            }
+        } else if (!m_isInitiator) {
+            if (m_isReceivingAudio) {
+                sdp &lt;&lt;
+                    &quot;m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0\r\n&quot;
+                    &quot;c=IN IP4 0.0.0.0\r\n&quot;
+                    &quot;a=rtcp-mux\r\n&quot;
+                    &quot;a=recvonly\r\n&quot;
+                    &quot;a=mid:part1\r\n&quot;
+                    &quot;a=rtpmap:111 OPUS/48000/2\r\n&quot;
+                    &quot;a=rtpmap:8 PCMA/8000\r\n&quot;
+                    &quot;a=rtpmap:0 PCMU/8000\r\n&quot;
+                    &quot;a=ssrc:3409173717 cname:/chKzCS9K6KOgL0m\r\n&quot;
+                    &quot;a=ice-ufrag:e/B1\r\n&quot;
+                    &quot;a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n&quot;
+                    &quot;a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n&quot;
+                    &quot;a=setup:active\r\n&quot;;
+            }
+            if (m_isReceivingVideo) {
+                sdp &lt;&lt;
+                    &quot;m=video 9 UDP/TLS/RTP/SAVPF 103 100 120\r\n&quot;
+                    &quot;c=IN IP4 0.0.0.0\r\n&quot;
+                    &quot;a=rtcp-mux\r\n&quot;
+                    &quot;a=recvonly\r\n&quot;
+                    &quot;a=mid:part2\r\n&quot;
+                    &quot;a=rtpmap:103 H264/90000\r\n&quot;
+                    &quot;a=rtpmap:100 VP8/90000\r\n&quot;
+                    &quot;a=rtpmap:120 RTX/90000\r\n&quot;
+                    &quot;a=fmtp:103 packetization-mode=1\r\n&quot;
+                    &quot;a=fmtp:120 apt=100;rtx-time=200\r\n&quot;
+                    &quot;a=rtcp-fb:100 nack\r\n&quot;
+                    &quot;a=rtcp-fb:103 nack pli\r\n&quot;
+                    &quot;a=rtcp-fb:100 nack pli\r\n&quot;
+                    &quot;a=rtcp-fb:103 ccm fir\r\n&quot;
+                    &quot;a=rtcp-fb:100 ccm fir\r\n&quot;
+                    &quot;a=ssrc:3409173718 cname:/chKzCS9K6KOgL0n\r\n&quot;
+                    &quot;a=ice-ufrag:e/B1\r\n&quot;
+                    &quot;a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n&quot;
+                    &quot;a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n&quot;
+                    &quot;a=setup:active\r\n&quot;;
+            }
+        }
+        MockLibWebRTCSessionDescription description(sdp.str());
+        observer-&gt;OnSuccess(&amp;description);
+    });
+}
+
+} // namespace WebCore
+
+#endif // USE(LIBWEBRTC)
</ins></span></pre></div>
<a id="trunkSourceWebCoretestingMockLibWebRTCPeerConnectionh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/testing/MockLibWebRTCPeerConnection.h (0 => 211253)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/MockLibWebRTCPeerConnection.h                                (rev 0)
+++ trunk/Source/WebCore/testing/MockLibWebRTCPeerConnection.h        2017-01-27 04:54:09 UTC (rev 211253)
</span><span class="lines">@@ -0,0 +1,229 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if USE(LIBWEBRTC)
+
+#include &quot;LibWebRTCMacros.h&quot;
+#include &lt;webrtc/api/mediastreaminterface.h&gt;
+#include &lt;webrtc/api/peerconnectioninterface.h&gt;
+#include &lt;wtf/text/WTFString.h&gt;
+
+namespace WebCore {
+
+class LibWebRTCProvider;
+
+void useMockRTCPeerConnectionFactory(LibWebRTCProvider*, const String&amp;);
+
+class MockLibWebRTCPeerConnection : public webrtc::PeerConnectionInterface {
+public:
+    virtual ~MockLibWebRTCPeerConnection() { }
+
+protected:
+    explicit MockLibWebRTCPeerConnection(webrtc::PeerConnectionObserver&amp; observer) : m_observer(observer) { }
+
+private:
+    rtc::scoped_refptr&lt;webrtc::StreamCollectionInterface&gt; local_streams() { return nullptr; }
+    rtc::scoped_refptr&lt;webrtc::StreamCollectionInterface&gt; remote_streams() { return nullptr; }
+    rtc::scoped_refptr&lt;webrtc::DtmfSenderInterface&gt; CreateDtmfSender(webrtc::AudioTrackInterface*) { return nullptr; }
+    bool GetStats(webrtc::StatsObserver*, webrtc::MediaStreamTrackInterface*, StatsOutputLevel) { return false; }
+    const webrtc::SessionDescriptionInterface* local_description() const { return nullptr; }
+    const webrtc::SessionDescriptionInterface* remote_description() const { return nullptr; }
+    bool AddIceCandidate(const webrtc::IceCandidateInterface*) { return true; }
+    void RegisterUMAObserver(webrtc::UMAObserver*) { }
+    SignalingState signaling_state() { return kStable; }
+    IceConnectionState ice_connection_state() { return kIceConnectionNew; }
+    IceGatheringState ice_gathering_state() { return kIceGatheringNew; }
+    void StopRtcEventLog() { }
+    void Close() { }
+
+protected:
+    void SetLocalDescription(webrtc::SetSessionDescriptionObserver*, webrtc::SessionDescriptionInterface*) final;
+    void SetRemoteDescription(webrtc::SetSessionDescriptionObserver*, webrtc::SessionDescriptionInterface*) final;
+    void CreateOffer(webrtc::CreateSessionDescriptionObserver*, const webrtc::MediaConstraintsInterface*) final;
+    void CreateAnswer(webrtc::CreateSessionDescriptionObserver*, const webrtc::MediaConstraintsInterface*) final;
+    rtc::scoped_refptr&lt;webrtc::DataChannelInterface&gt; CreateDataChannel(const std::string&amp;, const webrtc::DataChannelInit*) final;
+    bool AddStream(webrtc::MediaStreamInterface*) final;
+    void RemoveStream(webrtc::MediaStreamInterface*) final;
+
+    virtual void gotLocalDescription() { }
+
+    webrtc::PeerConnectionObserver&amp; m_observer;
+    unsigned m_counter { 0 };
+    rtc::scoped_refptr&lt;webrtc::MediaStreamInterface&gt; m_stream;
+    bool m_isInitiator { true };
+    bool m_isReceivingAudio { false };
+    bool m_isReceivingVideo { false };
+};
+
+class MockLibWebRTCSessionDescription: public webrtc::SessionDescriptionInterface {
+public:
+    explicit MockLibWebRTCSessionDescription(std::string&amp;&amp; sdp) : m_sdp(WTFMove(sdp)) { }
+
+private:
+    bool ToString(std::string* out) const final { *out = m_sdp; return true; }
+
+    cricket::SessionDescription* description() final { return nullptr; }
+    const cricket::SessionDescription* description() const final { return nullptr; }
+    std::string session_id() const final { return &quot;&quot;; }
+    std::string session_version() const final { return &quot;&quot;; }
+    std::string type() const final { return &quot;&quot;; }
+    bool AddCandidate(const webrtc::IceCandidateInterface*) final { return true; }
+    size_t number_of_mediasections() const final { return 0; }
+    const webrtc::IceCandidateCollection* candidates(size_t) const final { return nullptr; }
+
+    std::string m_sdp;
+};
+
+class MockLibWebRTCIceCandidate : public webrtc::IceCandidateInterface {
+public:
+    MockLibWebRTCIceCandidate(const char* sdp, const char* sdpMid)
+        : m_sdp(sdp)
+        , m_sdpMid(sdpMid) { }
+
+private:
+    std::string sdp_mid() const final { return m_sdpMid; }
+    int sdp_mline_index() const final { return 0; }
+    const cricket::Candidate&amp; candidate() const final { return m_candidate; }
+    bool ToString(std::string* out) const final { *out = m_sdp; return true; }
+
+protected:
+    const char* m_sdp;
+    const char* m_sdpMid;
+    cricket::Candidate m_candidate;
+};
+
+class MockLibWebRTCAudioTrack : public webrtc::AudioTrackInterface {
+public:
+    explicit MockLibWebRTCAudioTrack(const std::string&amp; id, webrtc::AudioSourceInterface* source)
+        : m_id(id)
+        , m_source(source) { }
+
+private:
+    webrtc::AudioSourceInterface* GetSource() const final { return m_source; }
+    void AddSink(webrtc::AudioTrackSinkInterface*) final { }
+    void RemoveSink(webrtc::AudioTrackSinkInterface*) final { }
+    void RegisterObserver(webrtc::ObserverInterface*) final { }
+    void UnregisterObserver(webrtc::ObserverInterface*) final { }
+
+    std::string kind() const final { return &quot;audio&quot;; }
+    std::string id() const final { return m_id; }
+    bool enabled() const final { return m_enabled; }
+    TrackState state() const final { return kLive; }
+    bool set_enabled(bool enabled) final { m_enabled = enabled; return true; }
+
+    bool m_enabled;
+    std::string m_id;
+    webrtc::AudioSourceInterface* m_source { nullptr };
+};
+
+class MockLibWebRTCVideoTrack : public webrtc::VideoTrackInterface {
+public:
+    explicit MockLibWebRTCVideoTrack(const std::string&amp; id, webrtc::VideoTrackSourceInterface* source)
+        : m_id(id)
+        , m_source(source) { }
+
+private:
+    webrtc::VideoTrackSourceInterface* GetSource() const final { return m_source; }
+    void RegisterObserver(webrtc::ObserverInterface*) final { }
+    void UnregisterObserver(webrtc::ObserverInterface*) final { }
+
+    std::string kind() const final { return &quot;video&quot;; }
+    std::string id() const final { return m_id; }
+    bool enabled() const final { return m_enabled; }
+    TrackState state() const final { return kLive; }
+    bool set_enabled(bool enabled) final { m_enabled = enabled; return true; }
+
+    bool m_enabled;
+    std::string m_id;
+    webrtc::VideoTrackSourceInterface* m_source { nullptr };
+};
+
+class MockLibWebRTCDataChannel : public webrtc::DataChannelInterface {
+public:
+    MockLibWebRTCDataChannel(std::string&amp;&amp; label, bool ordered, bool reliable, int id)
+        : m_label(WTFMove(label))
+        , m_ordered(ordered)
+        , m_reliable(reliable)
+        , m_id(id) { }
+
+private:
+    void RegisterObserver(webrtc::DataChannelObserver*) final { }
+    void UnregisterObserver() final { }
+    std::string label() const final { return m_label; }
+    bool reliable() const final { return m_reliable; }
+    bool ordered() const final { return m_ordered; }
+
+    int id() const final { return m_id; }
+    DataState state() const final { return kConnecting; }
+    uint64_t buffered_amount() const final { return 0; }
+    void Close() final { }
+    bool Send(const webrtc::DataBuffer&amp;) final { return true; }
+
+    std::string m_label;
+    bool m_ordered { true };
+    bool m_reliable { false };
+    int m_id { -1 };
+};
+
+class MockLibWebRTCPeerConnectionFactory : public webrtc::PeerConnectionFactoryInterface {
+public:
+    static rtc::scoped_refptr&lt;webrtc::PeerConnectionFactoryInterface&gt; create(LibWebRTCProvider* provider, String&amp;&amp; testCase) { return new rtc::RefCountedObject&lt;MockLibWebRTCPeerConnectionFactory&gt;(provider, WTFMove(testCase)); }
+
+protected:
+    MockLibWebRTCPeerConnectionFactory(LibWebRTCProvider*, String&amp;&amp;);
+
+private:
+    rtc::scoped_refptr&lt;webrtc::PeerConnectionInterface&gt; CreatePeerConnection(const webrtc::PeerConnectionInterface::RTCConfiguration&amp;, const webrtc::MediaConstraintsInterface*, std::unique_ptr&lt;cricket::PortAllocator&gt;, std::unique_ptr&lt;rtc::RTCCertificateGeneratorInterface&gt;, webrtc::PeerConnectionObserver*) final { return nullptr; }
+
+    rtc::scoped_refptr&lt;webrtc::PeerConnectionInterface&gt; CreatePeerConnection(const webrtc::PeerConnectionInterface::RTCConfiguration&amp;, std::unique_ptr&lt;cricket::PortAllocator&gt;, std::unique_ptr&lt;rtc::RTCCertificateGeneratorInterface&gt;, webrtc::PeerConnectionObserver*) final;
+
+    rtc::scoped_refptr&lt;webrtc::MediaStreamInterface&gt; CreateLocalMediaStream(const std::string&amp;) final;
+
+    void SetOptions(const Options&amp;) final { }
+    rtc::scoped_refptr&lt;webrtc::AudioSourceInterface&gt; CreateAudioSource(const cricket::AudioOptions&amp;) final { return nullptr; }
+    rtc::scoped_refptr&lt;webrtc::AudioSourceInterface&gt; CreateAudioSource(const webrtc::MediaConstraintsInterface*) final { return nullptr; }
+
+    rtc::scoped_refptr&lt;webrtc::VideoTrackSourceInterface&gt; CreateVideoSource(cricket::VideoCapturer*) final { return nullptr; }
+    rtc::scoped_refptr&lt;webrtc::VideoTrackSourceInterface&gt; CreateVideoSource(cricket::VideoCapturer*, const webrtc::MediaConstraintsInterface*) final { return nullptr; }
+
+    rtc::scoped_refptr&lt;webrtc::VideoTrackInterface&gt; CreateVideoTrack(const std::string&amp; id, webrtc::VideoTrackSourceInterface* source) final { return new rtc::RefCountedObject&lt;MockLibWebRTCVideoTrack&gt;(id, source); }
+    rtc::scoped_refptr&lt;webrtc::AudioTrackInterface&gt; CreateAudioTrack(const std::string&amp; id, webrtc::AudioSourceInterface* source) final { return new rtc::RefCountedObject&lt;MockLibWebRTCAudioTrack&gt;(id, source); }
+    bool StartAecDump(rtc::PlatformFile, int64_t) final { return false; }
+    void StopAecDump() final { }
+
+    bool StartRtcEventLog(rtc::PlatformFile, int64_t) final { return false; }
+    bool StartRtcEventLog(rtc::PlatformFile) final { return false; }
+    void StopRtcEventLog() final { }
+
+private:
+    LibWebRTCProvider* m_provider { nullptr };
+    String m_testCase;
+    unsigned m_numberOfRealPeerConnections { 0 };
+};
+
+} // namespace WebCore
+
+#endif // USE(LIBWEBRTC)
</ins></span></pre>
</div>
</div>

</body>
</html>