<!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>[214178] 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/214178">214178</a></dd>
<dt>Author</dt> <dd>eric.carlson@apple.com</dd>
<dt>Date</dt> <dd>2017-03-20 10:55:20 -0700 (Mon, 20 Mar 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>[MediaStream] Respect constraints passed to getUserMedia
https://bugs.webkit.org/show_bug.cgi?id=169870
&lt;rdar://problem/31138936&gt;

Reviewed by Youenn Fablet and Jer Noble.
Source/WebCore:

Remember the fitness score calculated when evaluating constraints passed to getUserMedia, so
the best device is chosen when more than one device supports the constraints. Register two
mock video and two mock audio devices with different capabilities so these changes can
be tested.

No new tests, existing tests updated.

* platform/mediastream/RealtimeMediaSource.cpp:
(WebCore::RealtimeMediaSource::selectSettings): Store fitness score in m_fitnessScore.
* platform/mediastream/RealtimeMediaSource.h:

* platform/mediastream/mac/MockRealtimeAudioSourceMac.h:
* platform/mediastream/mac/MockRealtimeAudioSourceMac.mm:
(WebCore::MockRealtimeAudioSource::create): Don't assume sampleRate is 44.1K
(WebCore::MockRealtimeAudioSourceMac::emitSampleBuffers): Use sampleRate() instead of m_sampleRate.
(WebCore::MockRealtimeAudioSourceMac::reconfigure): Ditto.
(WebCore::MockRealtimeAudioSourceMac::render): Ditto.
(WebCore::MockRealtimeAudioSourceMac::applySampleRate): Ditto.

* platform/mock/MockRealtimeAudioSource.cpp:
(WebCore::MockRealtimeAudioSource::updateSettings): Don't assume sampleRate is 44.1K
(WebCore::MockRealtimeAudioSource::initializeCapabilities): Support a range of sample rates.
(WebCore::MockRealtimeAudioSource::startProducingData): Initialize sampleRate if it hasn't
already been set.

* platform/mock/MockRealtimeMediaSource.cpp:
(WebCore::MockRealtimeMediaSource::audioDevices): Return an array of devices.
(WebCore::MockRealtimeMediaSource::videoDevices): Ditto.
(WebCore::MockRealtimeMediaSource::MockRealtimeMediaSource):
(WebCore::MockRealtimeMediaSource::mockAudioSourcePersistentID): Deleted.
(WebCore::MockRealtimeMediaSource::mockVideoSourcePersistentID): Deleted.
(WebCore::MockRealtimeMediaSource::mockAudioSourceName): Deleted.
(WebCore::MockRealtimeMediaSource::mockVideoSourceName): Deleted.
(WebCore::MockRealtimeMediaSource::audioDeviceInfo): Deleted.
(WebCore::MockRealtimeMediaSource::videoDeviceInfo): Deleted.
* platform/mock/MockRealtimeMediaSource.h:

* platform/mock/MockRealtimeMediaSourceCenter.cpp:
(WebCore::MockRealtimeMediaSourceCenter::validateRequestConstraints):
(WebCore::MockRealtimeMediaSourceCenter::createMediaStream):
(WebCore::MockRealtimeMediaSourceCenter::getMediaStreamDevices):
* platform/mock/MockRealtimeVideoSource.cpp:
(WebCore::MockRealtimeVideoSource::MockRealtimeVideoSource):

LayoutTests:

* fast/mediastream/MediaDevices-enumerateDevices-expected.txt:
* fast/mediastream/MediaDevices-getUserMedia-expected.txt:
* fast/mediastream/MediaDevices-getUserMedia.html:
* fast/mediastream/MediaStream-video-element-expected.txt:
* fast/mediastream/MediaStreamTrack-getCapabilities-expected.txt:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsfastmediastreamMediaDevicesenumerateDevicesexpectedtxt">trunk/LayoutTests/fast/mediastream/MediaDevices-enumerateDevices-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastmediastreamMediaDevicesenumerateDeviceshtml">trunk/LayoutTests/fast/mediastream/MediaDevices-enumerateDevices.html</a></li>
<li><a href="#trunkLayoutTestsfastmediastreamMediaDevicesgetUserMediaexpectedtxt">trunk/LayoutTests/fast/mediastream/MediaDevices-getUserMedia-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastmediastreamMediaDevicesgetUserMediahtml">trunk/LayoutTests/fast/mediastream/MediaDevices-getUserMedia.html</a></li>
<li><a href="#trunkLayoutTestsfastmediastreamMediaStreamvideoelementexpectedtxt">trunk/LayoutTests/fast/mediastream/MediaStream-video-element-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastmediastreamMediaStreamTrackgetCapabilitiesexpectedtxt">trunk/LayoutTests/fast/mediastream/MediaStreamTrack-getCapabilities-expected.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamRealtimeMediaSourcecpp">trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamRealtimeMediaSourceh">trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacMockRealtimeAudioSourceMach">trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacMockRealtimeAudioSourceMacmm">trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformmockMockRealtimeAudioSourcecpp">trunk/Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmockMockRealtimeMediaSourcecpp">trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmockMockRealtimeMediaSourceh">trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmockMockRealtimeMediaSourceCentercpp">trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmockMockRealtimeVideoSourcecpp">trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/LayoutTests/ChangeLog        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2017-03-20  Eric Carlson  &lt;eric.carlson@apple.com&gt;
+
+        [MediaStream] Respect constraints passed to getUserMedia
+        https://bugs.webkit.org/show_bug.cgi?id=169870
+        &lt;rdar://problem/31138936&gt;
+
+        Reviewed by Youenn Fablet and Jer Noble.
+
+        * fast/mediastream/MediaDevices-enumerateDevices-expected.txt:
+        * fast/mediastream/MediaDevices-getUserMedia-expected.txt:
+        * fast/mediastream/MediaDevices-getUserMedia.html:
+        * fast/mediastream/MediaStream-video-element-expected.txt:
+        * fast/mediastream/MediaStreamTrack-getCapabilities-expected.txt:
+
</ins><span class="cx"> 2017-03-20  Ryan Haddad  &lt;ryanhaddad@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Mark imported/w3c/web-platform-tests/XMLHttpRequest/timeout-multiple-fetches.html as flaky.
</span></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamMediaDevicesenumerateDevicesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/mediastream/MediaDevices-enumerateDevices-expected.txt (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/MediaDevices-enumerateDevices-expected.txt        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/LayoutTests/fast/mediastream/MediaDevices-enumerateDevices-expected.txt        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -23,7 +23,19 @@
</span><span class="cx"> PASS captureDevice.label is &quot;&quot;
</span><span class="cx"> PASS captureDevice.groupId is non-null.
</span><span class="cx"> 
</span><ins>+PASS captureDevice.kind is non-null.
+PASS captureDevice.deviceId is non-null.
+PASS captureDevice.label is non-null.
+PASS captureDevice.label is &quot;&quot;
+PASS captureDevice.groupId is non-null.
</ins><span class="cx"> 
</span><ins>+PASS captureDevice.kind is non-null.
+PASS captureDevice.deviceId is non-null.
+PASS captureDevice.label is non-null.
+PASS captureDevice.label is &quot;&quot;
+PASS captureDevice.groupId is non-null.
+
+
</ins><span class="cx"> *** Calling mediaDevices.enumerateDevices with persistent access, and without a media stream track
</span><span class="cx"> 
</span><span class="cx"> PASS captureDevices.length is non-zero.
</span><span class="lines">@@ -42,7 +54,21 @@
</span><span class="cx"> PASS captureDevice.groupId is non-null.
</span><span class="cx"> PASS deviceIds.indexOf(captureDevice.deviceId) is not -1
</span><span class="cx"> 
</span><ins>+PASS captureDevice.kind is non-null.
+PASS captureDevice.deviceId is non-null.
+PASS captureDevice.label is non-null.
+PASS captureDevice.label is not &quot;&quot;
+PASS captureDevice.groupId is non-null.
+PASS deviceIds.indexOf(captureDevice.deviceId) is not -1
</ins><span class="cx"> 
</span><ins>+PASS captureDevice.kind is non-null.
+PASS captureDevice.deviceId is non-null.
+PASS captureDevice.label is non-null.
+PASS captureDevice.label is not &quot;&quot;
+PASS captureDevice.groupId is non-null.
+PASS deviceIds.indexOf(captureDevice.deviceId) is not -1
+
+
</ins><span class="cx"> *** Calling mediaDevices.enumerateDevices without persistent access, with a media stream track
</span><span class="cx"> 
</span><span class="cx"> PASS captureDevices.length is non-zero.
</span><span class="lines">@@ -61,6 +87,20 @@
</span><span class="cx"> PASS captureDevice.groupId is non-null.
</span><span class="cx"> PASS deviceIds.indexOf(captureDevice.deviceId) is not -1
</span><span class="cx"> 
</span><ins>+PASS captureDevice.kind is non-null.
+PASS captureDevice.deviceId is non-null.
+PASS captureDevice.label is non-null.
+PASS captureDevice.label is not &quot;&quot;
+PASS captureDevice.groupId is non-null.
+PASS deviceIds.indexOf(captureDevice.deviceId) is not -1
+
+PASS captureDevice.kind is non-null.
+PASS captureDevice.deviceId is non-null.
+PASS captureDevice.label is non-null.
+PASS captureDevice.label is not &quot;&quot;
+PASS captureDevice.groupId is non-null.
+PASS deviceIds.indexOf(captureDevice.deviceId) is not -1
+
</ins><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span><span class="cx"> TEST COMPLETE
</span></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamMediaDevicesenumerateDeviceshtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/mediastream/MediaDevices-enumerateDevices.html (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/MediaDevices-enumerateDevices.html        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/LayoutTests/fast/mediastream/MediaDevices-enumerateDevices.html        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -37,7 +37,7 @@
</span><span class="cx">                                 shouldBeEmptyString(&quot;captureDevice.label&quot;);
</span><span class="cx">                             shouldBeNonNull(&quot;captureDevice.groupId&quot;);
</span><span class="cx">                             
</span><del>-                            if (deviceIds.length &lt; 2)
</del><ins>+                            if (deviceIds.length &lt; 4)
</ins><span class="cx">                                 deviceIds.push(captureDevice.deviceId);
</span><span class="cx">                             else
</span><span class="cx">                                 shouldNotBe(&quot;deviceIds.indexOf(captureDevice.deviceId)&quot;, &quot;-1&quot;);
</span></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamMediaDevicesgetUserMediaexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/mediastream/MediaDevices-getUserMedia-expected.txt (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/MediaDevices-getUserMedia-expected.txt        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/LayoutTests/fast/mediastream/MediaDevices-getUserMedia-expected.txt        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -4,35 +4,53 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> PASS typeof navigator.mediaDevices.webkitGetUserMedia is 'undefined'
</span><ins>+
</ins><span class="cx"> PASS navigator.mediaDevices.getUserMedia({audio:true}).then(gotStream1); did not throw exception.
</span><span class="cx"> PASS navigator.mediaDevices.getUserMedia() rejected with error: TypeError: Type error
</span><span class="cx"> PASS navigator.mediaDevices.getUserMedia({}) rejected with error: TypeError: Type error
</span><span class="cx"> PASS navigator.mediaDevices.getUserMedia.apply(undefined) rejected with error: TypeError: Can only call MediaDevices.getUserMedia on instances of MediaDevices
</span><del>-PASS Stream generated.
</del><ins>+PASS Stream 1 generated.
</ins><span class="cx"> PASS stream.getAudioTracks().length is 1
</span><span class="cx"> PASS stream.getVideoTracks().length is 0
</span><ins>+
</ins><span class="cx"> PASS navigator.mediaDevices.getUserMedia({video:true}).then(gotStream2); did not throw exception.
</span><del>-PASS Stream generated.
</del><ins>+PASS Stream 2 generated.
</ins><span class="cx"> PASS stream.getAudioTracks().length is 0
</span><span class="cx"> PASS stream.getVideoTracks().length is 1
</span><ins>+
</ins><span class="cx"> PASS navigator.mediaDevices.getUserMedia({audio:true, video:true}).then(gotStream3); did not throw exception.
</span><del>-PASS Stream generated.
</del><ins>+PASS Stream 3 generated.
</ins><span class="cx"> PASS stream.getAudioTracks().length is 1
</span><span class="cx"> PASS stream.getVideoTracks().length is 1
</span><ins>+
</ins><span class="cx"> PASS navigator.mediaDevices.getUserMedia({audio:{}, video:{}}).then(gotStream4); did not throw exception.
</span><del>-PASS Stream generated.
</del><ins>+PASS Stream 4 generated.
</ins><span class="cx"> PASS stream.getAudioTracks().length is 1
</span><span class="cx"> PASS stream.getVideoTracks().length is 1
</span><del>-PASS navigator.mediaDevices.getUserMedia({audio:audioConstraints, video:false}).then(gotStreamWithConstraints1) did not throw exception.
-PASS Stream generated.
-PASS navigator.mediaDevices.getUserMedia({audio:false, video:videoConstraints}).then(gotStreamWithConstraints2) did not throw exception.
-PASS Stream generated.
</del><ins>+
+PASS navigator.mediaDevices.getUserMedia({audio:audioConstraints}).then(gotStreamWithConstraints1) did not throw exception.
+PASS Stream 5 generated.
+PASS stream.getAudioTracks().length is 1
+PASS stream.getVideoTracks().length is 0
+
+PASS navigator.mediaDevices.getUserMedia({video:videoConstraints}).then(gotStreamWithConstraints2) did not throw exception.
+PASS Stream 6 generated.
+PASS stream.getAudioTracks().length is 0
+PASS stream.getVideoTracks().length is 1
+
+PASS navigator.mediaDevices.getUserMedia({video:videoConstraints}).then(gotStreamWithConstraints3).catch(error1) did not throw exception.
+PASS Stream 7 generated.
+PASS stream.getVideoTracks()[0].getSettings().facingMode is &quot;user&quot;
+PASS stream.getAudioTracks().length is 0
+
</ins><span class="cx"> PASS navigator.mediaDevices.getUserMedia({audio:audioConstraints, video:false}).then(invalidGotStream).catch(errorWithConstraints1) did not throw exception.
</span><span class="cx"> PASS Error callback called.
</span><ins>+
</ins><span class="cx"> PASS navigator.mediaDevices.getUserMedia({audio:false, video:videoConstraints}).then(invalidGotStream).catch(errorWithConstraints2) did not throw exception.
</span><span class="cx"> PASS Error callback called.
</span><span class="cx"> PASS errorArg.name is &quot;Error&quot;
</span><del>-PASS navigator.mediaDevices.getUserMedia({audio:true}).then(validStream, error1); did not throw exception.
</del><ins>+
+PASS navigator.mediaDevices.getUserMedia({audio:true}).then(validStream).catch(error1); did not throw exception.
</ins><span class="cx"> PASS Stream generated because page has already authenticated.
</span><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamMediaDevicesgetUserMediahtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/mediastream/MediaDevices-getUserMedia.html (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/MediaDevices-getUserMedia.html        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/LayoutTests/fast/mediastream/MediaDevices-getUserMedia.html        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             function error1(e) {
</span><del>-                testFailed(&quot;Error callback called.&quot;);
</del><ins>+                testFailed(`Error callback called, error = ${e}`);
</ins><span class="cx">                 finishJSTest();
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="lines">@@ -46,7 +46,8 @@
</span><span class="cx">                 // as it should not see the request because the current browsing context has already
</span><span class="cx">                 // successfully created a stream for the mock audio device.
</span><span class="cx">                 setUserMediaPermission(false);
</span><del>-                shouldNotThrow(&quot;navigator.mediaDevices.getUserMedia({audio:true}).then(validStream, error1);&quot;);
</del><ins>+                debug(&quot;&quot;);
+                shouldNotThrow(&quot;navigator.mediaDevices.getUserMedia({audio:true}).then(validStream).catch(error1);&quot;);
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             function errorWithConstraints1() {
</span><span class="lines">@@ -59,12 +60,17 @@
</span><span class="cx">                     },
</span><span class="cx">                     height: 11
</span><span class="cx">                 };
</span><ins>+                debug(&quot;&quot;);
</ins><span class="cx">                 shouldNotThrow(&quot;navigator.mediaDevices.getUserMedia({audio:false, video:videoConstraints}).then(invalidGotStream).catch(errorWithConstraints2)&quot;);
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            function gotStreamWithConstraints2() {
-                testPassed(&quot;Stream generated.&quot;);
</del><ins>+            function gotStreamWithConstraints3(s) {
+                stream = s;
+                testPassed(&quot;Stream 7 generated.&quot;);
</ins><span class="cx"> 
</span><ins>+                shouldBeEqualToString(&quot;stream.getVideoTracks()[0].getSettings().facingMode&quot;, &quot;user&quot;);
+                shouldBe(&quot;stream.getAudioTracks().length&quot;, &quot;0&quot;);
+
</ins><span class="cx">                 audioConstraints = {
</span><span class="cx">                     sampleRate: {
</span><span class="cx">                         min: .6,
</span><span class="lines">@@ -72,16 +78,37 @@
</span><span class="cx">                         ideal: 1.0
</span><span class="cx">                     },
</span><span class="cx">                     sampleRate: {
</span><del>-                        exact: 48000
</del><ins>+                        exact: 88000
</ins><span class="cx">                     }
</span><span class="cx">                 };
</span><ins>+                debug(&quot;&quot;);
</ins><span class="cx">                 shouldNotThrow(&quot;navigator.mediaDevices.getUserMedia({audio:audioConstraints, video:false}).then(invalidGotStream).catch(errorWithConstraints1)&quot;);
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            function gotStreamWithConstraints1() {
-                testPassed(&quot;Stream generated.&quot;);
</del><ins>+            function gotStreamWithConstraints2(s) {
+                stream = s;
+                testPassed(&quot;Stream 6 generated.&quot;);
</ins><span class="cx"> 
</span><ins>+                shouldBe(&quot;stream.getAudioTracks().length&quot;, &quot;0&quot;);
+                shouldBe(&quot;stream.getVideoTracks().length&quot;, &quot;1&quot;);
+
</ins><span class="cx">                 videoConstraints = {
</span><ins>+                    facingMode: {
+                        exact: ['user']
+                    },
+                };
+                debug(&quot;&quot;);
+                shouldNotThrow(&quot;navigator.mediaDevices.getUserMedia({video:videoConstraints}).then(gotStreamWithConstraints3).catch(error1)&quot;);
+            }
+
+            function gotStreamWithConstraints1(s) {
+                stream = s;
+                testPassed(&quot;Stream 5 generated.&quot;);
+
+                shouldBe(&quot;stream.getAudioTracks().length&quot;, &quot;1&quot;);
+                shouldBe(&quot;stream.getVideoTracks().length&quot;, &quot;0&quot;);
+
+                videoConstraints = {
</ins><span class="cx">                     width: {
</span><span class="cx">                         min: 400,
</span><span class="cx">                         exact: 400,
</span><span class="lines">@@ -93,12 +120,13 @@
</span><span class="cx">                         exact: ['environment']
</span><span class="cx">                     }
</span><span class="cx">                 };
</span><del>-                shouldNotThrow(&quot;navigator.mediaDevices.getUserMedia({audio:false, video:videoConstraints}).then(gotStreamWithConstraints2)&quot;);
</del><ins>+                debug(&quot;&quot;);
+                shouldNotThrow(&quot;navigator.mediaDevices.getUserMedia({video:videoConstraints}).then(gotStreamWithConstraints2)&quot;);
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             function gotStream4(s) {
</span><span class="cx">                 stream = s;
</span><del>-                testPassed(&quot;Stream generated.&quot;);
</del><ins>+                testPassed(&quot;Stream 4 generated.&quot;);
</ins><span class="cx">                 shouldBe(&quot;stream.getAudioTracks().length&quot;, &quot;1&quot;);
</span><span class="cx">                 shouldBe(&quot;stream.getVideoTracks().length&quot;, &quot;1&quot;);
</span><span class="cx"> 
</span><span class="lines">@@ -111,33 +139,37 @@
</span><span class="cx">                     },
</span><span class="cx">                     sampleSize: 11
</span><span class="cx">                 };
</span><del>-                shouldNotThrow(&quot;navigator.mediaDevices.getUserMedia({audio:audioConstraints, video:false}).then(gotStreamWithConstraints1)&quot;);
</del><ins>+                debug(&quot;&quot;);
+                shouldNotThrow(&quot;navigator.mediaDevices.getUserMedia({audio:audioConstraints}).then(gotStreamWithConstraints1)&quot;);
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             function gotStream3(s) {
</span><span class="cx">                 stream = s;
</span><del>-                testPassed(&quot;Stream generated.&quot;);
</del><ins>+                testPassed(&quot;Stream 3 generated.&quot;);
</ins><span class="cx">                 shouldBe(&quot;stream.getAudioTracks().length&quot;, &quot;1&quot;);
</span><span class="cx">                 shouldBe(&quot;stream.getVideoTracks().length&quot;, &quot;1&quot;);
</span><span class="cx"> 
</span><ins>+                debug(&quot;&quot;);
</ins><span class="cx">                 shouldNotThrow(&quot;navigator.mediaDevices.getUserMedia({audio:{}, video:{}}).then(gotStream4);&quot;);
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             function gotStream2(s) {
</span><span class="cx">                 stream = s;
</span><del>-                testPassed(&quot;Stream generated.&quot;);
</del><ins>+                testPassed(&quot;Stream 2 generated.&quot;);
</ins><span class="cx">                 shouldBe(&quot;stream.getAudioTracks().length&quot;, &quot;0&quot;);
</span><span class="cx">                 shouldBe(&quot;stream.getVideoTracks().length&quot;, &quot;1&quot;);
</span><span class="cx"> 
</span><ins>+                debug(&quot;&quot;);
</ins><span class="cx">                 shouldNotThrow(&quot;navigator.mediaDevices.getUserMedia({audio:true, video:true}).then(gotStream3);&quot;);
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             function gotStream1(s) {
</span><span class="cx">                 stream = s;
</span><del>-                testPassed(&quot;Stream generated.&quot;);
</del><ins>+                testPassed(&quot;Stream 1 generated.&quot;);
</ins><span class="cx">                 shouldBe(&quot;stream.getAudioTracks().length&quot;, &quot;1&quot;);
</span><span class="cx">                 shouldBe(&quot;stream.getVideoTracks().length&quot;, &quot;0&quot;);
</span><span class="cx"> 
</span><ins>+                debug(&quot;&quot;);
</ins><span class="cx">                 shouldNotThrow(&quot;navigator.mediaDevices.getUserMedia({video:true}).then(gotStream2);&quot;)
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="lines">@@ -149,6 +181,7 @@
</span><span class="cx">             });
</span><span class="cx">             shouldBe(&quot;typeof navigator.mediaDevices.webkitGetUserMedia&quot;, &quot;'undefined'&quot;);
</span><span class="cx">             setUserMediaPermission(true);
</span><ins>+            debug(&quot;&quot;);
</ins><span class="cx">             shouldNotThrow(&quot;navigator.mediaDevices.getUserMedia({audio:true}).then(gotStream1);&quot;);
</span><span class="cx">             navigator.mediaDevices.getUserMedia.apply(undefined, {audio:true}).then(invalidGotStream, function(error) {
</span><span class="cx">                  testPassed(&quot;navigator.mediaDevices.getUserMedia.apply(undefined) rejected with error: &quot; + error);
</span></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamMediaStreamvideoelementexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/mediastream/MediaStream-video-element-expected.txt (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/MediaStream-video-element-expected.txt        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/LayoutTests/fast/mediastream/MediaStream-video-element-expected.txt        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -34,7 +34,7 @@
</span><span class="cx"> video.videoTracks[0] properties:
</span><span class="cx">   track.id = &lt;UUID&gt;
</span><span class="cx">   track.kind = main
</span><del>-  track.label = Mock video device
</del><ins>+  track.label = Mock video device 1
</ins><span class="cx">   track.language = 
</span><span class="cx">   track.selected = true
</span><span class="cx">   track.sourceBuffer = null
</span><span class="lines">@@ -48,7 +48,7 @@
</span><span class="cx"> video.audioTracks[0] properties:
</span><span class="cx">   track.id = &lt;UUID&gt;
</span><span class="cx">   track.kind = main
</span><del>-  track.label = Mock audio device
</del><ins>+  track.label = Mock audio device 1
</ins><span class="cx">   track.language = 
</span><span class="cx">   track.enabled = true
</span><span class="cx">   track.sourceBuffer = null
</span></span></pre></div>
<a id="trunkLayoutTestsfastmediastreamMediaStreamTrackgetCapabilitiesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/mediastream/MediaStreamTrack-getCapabilities-expected.txt (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/mediastream/MediaStreamTrack-getCapabilities-expected.txt        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/LayoutTests/fast/mediastream/MediaStreamTrack-getCapabilities-expected.txt        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -14,7 +14,7 @@
</span><span class="cx"> audio track capabilities:
</span><span class="cx">   capabilities.deviceId = &lt;UUID&gt;
</span><span class="cx">   capabilities.echoCancellation = [ true, true ]
</span><del>-  capabilities.sampleRate = { max: 44100, min: 44100 }
</del><ins>+  capabilities.sampleRate = { max: 48000, min: 44100 }
</ins><span class="cx">   capabilities.volume = { max: 1, min: 0 }
</span><span class="cx"> 
</span><span class="cx"> PASS successfullyParsed is true
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/Source/WebCore/ChangeLog        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -1,3 +1,55 @@
</span><ins>+2017-03-20  Eric Carlson  &lt;eric.carlson@apple.com&gt;
+
+        [MediaStream] Respect constraints passed to getUserMedia
+        https://bugs.webkit.org/show_bug.cgi?id=169870
+        &lt;rdar://problem/31138936&gt;
+
+        Reviewed by Youenn Fablet and Jer Noble.
+        
+        Remember the fitness score calculated when evaluating constraints passed to getUserMedia, so
+        the best device is chosen when more than one device supports the constraints. Register two
+        mock video and two mock audio devices with different capabilities so these changes can 
+        be tested.
+
+        No new tests, existing tests updated.
+
+        * platform/mediastream/RealtimeMediaSource.cpp:
+        (WebCore::RealtimeMediaSource::selectSettings): Store fitness score in m_fitnessScore.
+        * platform/mediastream/RealtimeMediaSource.h:
+
+        * platform/mediastream/mac/MockRealtimeAudioSourceMac.h:
+        * platform/mediastream/mac/MockRealtimeAudioSourceMac.mm:
+        (WebCore::MockRealtimeAudioSource::create): Don't assume sampleRate is 44.1K
+        (WebCore::MockRealtimeAudioSourceMac::emitSampleBuffers): Use sampleRate() instead of m_sampleRate.
+        (WebCore::MockRealtimeAudioSourceMac::reconfigure): Ditto.
+        (WebCore::MockRealtimeAudioSourceMac::render): Ditto.
+        (WebCore::MockRealtimeAudioSourceMac::applySampleRate): Ditto.
+
+        * platform/mock/MockRealtimeAudioSource.cpp:
+        (WebCore::MockRealtimeAudioSource::updateSettings): Don't assume sampleRate is 44.1K
+        (WebCore::MockRealtimeAudioSource::initializeCapabilities): Support a range of sample rates.
+        (WebCore::MockRealtimeAudioSource::startProducingData): Initialize sampleRate if it hasn't
+        already been set.
+
+        * platform/mock/MockRealtimeMediaSource.cpp:
+        (WebCore::MockRealtimeMediaSource::audioDevices): Return an array of devices.
+        (WebCore::MockRealtimeMediaSource::videoDevices): Ditto.
+        (WebCore::MockRealtimeMediaSource::MockRealtimeMediaSource):
+        (WebCore::MockRealtimeMediaSource::mockAudioSourcePersistentID): Deleted.
+        (WebCore::MockRealtimeMediaSource::mockVideoSourcePersistentID): Deleted.
+        (WebCore::MockRealtimeMediaSource::mockAudioSourceName): Deleted.
+        (WebCore::MockRealtimeMediaSource::mockVideoSourceName): Deleted.
+        (WebCore::MockRealtimeMediaSource::audioDeviceInfo): Deleted.
+        (WebCore::MockRealtimeMediaSource::videoDeviceInfo): Deleted.
+        * platform/mock/MockRealtimeMediaSource.h:
+
+        * platform/mock/MockRealtimeMediaSourceCenter.cpp:
+        (WebCore::MockRealtimeMediaSourceCenter::validateRequestConstraints):
+        (WebCore::MockRealtimeMediaSourceCenter::createMediaStream):
+        (WebCore::MockRealtimeMediaSourceCenter::getMediaStreamDevices):
+        * platform/mock/MockRealtimeVideoSource.cpp:
+        (WebCore::MockRealtimeVideoSource::MockRealtimeVideoSource):
+
</ins><span class="cx"> 2017-03-20  Wenson Hsieh  &lt;wenson_hsieh@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         TextIndicator should support a mode where selection rects are used to size the snapshot
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamRealtimeMediaSourcecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -548,7 +548,7 @@
</span><span class="cx">     // 5.1 compute the fitness distance between it and each settings dictionary in candidates, treating bare
</span><span class="cx">     //     values of properties as exact.
</span><span class="cx">     Vector&lt;std::pair&lt;double, MediaTrackConstraintSetMap&gt;&gt; supportedConstraints;
</span><del>-    double minimumDistance = std::numeric_limits&lt;double&gt;::infinity();
</del><ins>+    m_fitnessScore = std::numeric_limits&lt;double&gt;::infinity();
</ins><span class="cx"> 
</span><span class="cx">     for (const auto&amp; advancedConstraint : constraints.advancedConstraints()) {
</span><span class="cx">         double constraintDistance = 0;
</span><span class="lines">@@ -561,8 +561,8 @@
</span><span class="cx">                 supported = true;
</span><span class="cx">         });
</span><span class="cx"> 
</span><del>-        if (constraintDistance &lt; minimumDistance)
-            minimumDistance = constraintDistance;
</del><ins>+        if (constraintDistance &lt; m_fitnessScore)
+            m_fitnessScore = constraintDistance;
</ins><span class="cx"> 
</span><span class="cx">         // 5.2 If the fitness distance is finite for one or more settings dictionaries in candidates, keep those
</span><span class="cx">         //     settings dictionaries in candidates, discarding others.
</span><span class="lines">@@ -573,9 +573,9 @@
</span><span class="cx"> 
</span><span class="cx">     // 6. Select one settings dictionary from candidates, and return it as the result of the SelectSettings() algorithm.
</span><span class="cx">     //    The UA should use the one with the smallest fitness distance, as calculated in step 3.
</span><del>-    if (!std::isinf(minimumDistance)) {
</del><ins>+    if (!std::isinf(m_fitnessScore)) {
</ins><span class="cx">         supportedConstraints.removeAllMatching([&amp;](const std::pair&lt;double, MediaTrackConstraintSetMap&gt;&amp; pair) -&gt; bool {
</span><del>-            return pair.first &gt; minimumDistance;
</del><ins>+            return pair.first &gt; m_fitnessScore;
</ins><span class="cx">         });
</span><span class="cx"> 
</span><span class="cx">         if (!supportedConstraints.isEmpty()) {
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamRealtimeMediaSourceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -106,7 +106,6 @@
</span><span class="cx">     virtual void setName(const String&amp; name) { m_name = name; }
</span><span class="cx">     
</span><span class="cx">     virtual unsigned fitnessScore() const { return m_fitnessScore; }
</span><del>-    virtual void setFitnessScore(const unsigned fitnessScore) { m_fitnessScore = fitnessScore; }
</del><span class="cx"> 
</span><span class="cx">     virtual RefPtr&lt;RealtimeMediaSourceCapabilities&gt; capabilities() const = 0;
</span><span class="cx">     virtual const RealtimeMediaSourceSettings&amp; settings() const = 0;
</span><span class="lines">@@ -219,7 +218,7 @@
</span><span class="cx">     double m_volume { 1 };
</span><span class="cx">     double m_sampleRate { 0 };
</span><span class="cx">     double m_sampleSize { 0 };
</span><del>-    unsigned m_fitnessScore { 0 };
</del><ins>+    double m_fitnessScore { std::numeric_limits&lt;double&gt;::infinity() };
</ins><span class="cx">     RealtimeMediaSourceSettings::VideoFacingMode m_facingMode { RealtimeMediaSourceSettings::User};
</span><span class="cx"> 
</span><span class="cx">     bool m_echoCancellation { false };
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacMockRealtimeAudioSourceMach"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.h (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.h        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.h        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -61,11 +61,9 @@
</span><span class="cx"> 
</span><span class="cx">     AudioSourceProvider* audioSourceProvider() final;
</span><span class="cx"> 
</span><del>-    size_t m_audioBufferListBufferSize { 0 };
</del><span class="cx">     std::unique_ptr&lt;WebAudioBufferList&gt; m_audioBufferList;
</span><span class="cx"> 
</span><span class="cx">     uint32_t m_maximiumFrameCount;
</span><del>-    uint32_t m_sampleRate { 0 };
</del><span class="cx">     uint64_t m_samplesEmitted { 0 };
</span><span class="cx">     uint64_t m_samplesRendered { 0 };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacMockRealtimeAudioSourceMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -90,8 +90,6 @@
</span><span class="cx">     if (constraints &amp;&amp; source-&gt;applyConstraints(*constraints))
</span><span class="cx">         source = nullptr;
</span><span class="cx"> 
</span><del>-    source-&gt;applySampleRate(44100);
-
</del><span class="cx">     return source;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -119,7 +117,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_formatDescription);
</span><span class="cx"> 
</span><del>-    CMTime startTime = CMTimeMake(m_samplesEmitted, m_sampleRate);
</del><ins>+    CMTime startTime = CMTimeMake(m_samplesEmitted, sampleRate());
</ins><span class="cx">     m_samplesEmitted += frameCount;
</span><span class="cx"> 
</span><span class="cx">     audioSamplesAvailable(toMediaTime(startTime), *m_audioBufferList, CAAudioStreamDescription(m_streamFormat), frameCount);
</span><span class="lines">@@ -127,7 +125,7 @@
</span><span class="cx"> 
</span><span class="cx"> void MockRealtimeAudioSourceMac::reconfigure()
</span><span class="cx"> {
</span><del>-    m_maximiumFrameCount = WTF::roundUpToPowerOfTwo(renderInterval() / 1000. * m_sampleRate * 2);
</del><ins>+    m_maximiumFrameCount = WTF::roundUpToPowerOfTwo(renderInterval() / 1000. * sampleRate() * 2);
</ins><span class="cx">     ASSERT(m_maximiumFrameCount);
</span><span class="cx"> 
</span><span class="cx">     const int bytesPerFloat = sizeof(Float32);
</span><span class="lines">@@ -136,7 +134,7 @@
</span><span class="cx">     const bool isFloat = true;
</span><span class="cx">     const bool isBigEndian = false;
</span><span class="cx">     const bool isNonInterleaved = true;
</span><del>-    FillOutASBDForLPCM(m_streamFormat, m_sampleRate, channelCount, bitsPerByte * bytesPerFloat, bitsPerByte * bytesPerFloat, isFloat, isBigEndian, isNonInterleaved);
</del><ins>+    FillOutASBDForLPCM(m_streamFormat, sampleRate(), channelCount, bitsPerByte * bytesPerFloat, bitsPerByte * bytesPerFloat, isFloat, isBigEndian, isNonInterleaved);
</ins><span class="cx"> 
</span><span class="cx">     m_audioBufferList = std::make_unique&lt;WebAudioBufferList&gt;(m_streamFormat, m_streamFormat.mBytesPerFrame * m_maximiumFrameCount);
</span><span class="cx"> 
</span><span class="lines">@@ -150,7 +148,7 @@
</span><span class="cx">     if (!m_audioBufferList)
</span><span class="cx">         reconfigure();
</span><span class="cx"> 
</span><del>-    uint32_t totalFrameCount = alignTo16Bytes(delta * m_sampleRate);
</del><ins>+    uint32_t totalFrameCount = alignTo16Bytes(delta * sampleRate());
</ins><span class="cx">     uint32_t frameCount = std::min(totalFrameCount, m_maximiumFrameCount);
</span><span class="cx"> 
</span><span class="cx">     while (frameCount) {
</span><span class="lines">@@ -161,7 +159,7 @@
</span><span class="cx">             audioBuffer.mDataByteSize = frameCount * m_streamFormat.mBytesPerFrame;
</span><span class="cx">             if (!m_muted &amp;&amp; m_enabled) {
</span><span class="cx">                 memcpy(audioBuffer.mData, &amp;m_bipBopBuffer[bipBopStart], sizeof(Float32) * bipBopCount);
</span><del>-                addHum(HumVolume, HumFrequency, m_sampleRate, m_samplesRendered, static_cast&lt;float*&gt;(audioBuffer.mData), bipBopCount);
</del><ins>+                addHum(HumVolume, HumFrequency, sampleRate(), m_samplesRendered, static_cast&lt;float*&gt;(audioBuffer.mData), bipBopCount);
</ins><span class="cx">             } else
</span><span class="cx">                 memset(audioBuffer.mData, 0, sizeof(Float32) * bipBopCount);
</span><span class="cx">         }
</span><span class="lines">@@ -177,25 +175,23 @@
</span><span class="cx">     if (sampleRate &lt; 44100 || sampleRate &gt; 48000)
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    if (static_cast&lt;uint32_t&gt;(sampleRate) == m_sampleRate)
</del><ins>+    if (sampleRate == this-&gt;sampleRate())
</ins><span class="cx">         return true;
</span><span class="cx"> 
</span><del>-    m_sampleRate = sampleRate;
</del><span class="cx">     m_formatDescription = nullptr;
</span><span class="cx">     m_audioBufferList = nullptr;
</span><del>-    m_audioBufferListBufferSize = 0;
</del><span class="cx"> 
</span><del>-    size_t sampleCount = 2 * m_sampleRate;
</del><ins>+    size_t sampleCount = 2 * sampleRate;
</ins><span class="cx"> 
</span><span class="cx">     m_bipBopBuffer.grow(sampleCount);
</span><span class="cx">     m_bipBopBuffer.fill(0);
</span><span class="cx"> 
</span><del>-    size_t bipBopSampleCount = ceil(BipBopDuration * m_sampleRate);
</del><ins>+    size_t bipBopSampleCount = ceil(BipBopDuration * sampleRate);
</ins><span class="cx">     size_t bipStart = 0;
</span><del>-    size_t bopStart = m_sampleRate;
</del><ins>+    size_t bopStart = sampleRate;
</ins><span class="cx"> 
</span><del>-    addHum(BipBopVolume, BipFrequency, m_sampleRate, 0, m_bipBopBuffer.data() + bipStart, bipBopSampleCount);
-    addHum(BipBopVolume, BopFrequency, m_sampleRate, 0, m_bipBopBuffer.data() + bopStart, bipBopSampleCount);
</del><ins>+    addHum(BipBopVolume, BipFrequency, sampleRate, 0, m_bipBopBuffer.data() + bipStart, bipBopSampleCount);
+    addHum(BipBopVolume, BopFrequency, sampleRate, 0, m_bipBopBuffer.data() + bopStart, bipBopSampleCount);
</ins><span class="cx"> 
</span><span class="cx">     return true;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmockMockRealtimeAudioSourcecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -84,7 +84,7 @@
</span><span class="cx"> {
</span><span class="cx">     settings.setVolume(volume());
</span><span class="cx">     settings.setEchoCancellation(echoCancellation());
</span><del>-    settings.setSampleRate(44100);
</del><ins>+    settings.setSampleRate(sampleRate());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void MockRealtimeAudioSource::initializeCapabilities(RealtimeMediaSourceCapabilities&amp; capabilities)
</span><span class="lines">@@ -91,7 +91,7 @@
</span><span class="cx"> {
</span><span class="cx">     capabilities.setVolume(CapabilityValueOrRange(0.0, 1.0));
</span><span class="cx">     capabilities.setEchoCancellation(RealtimeMediaSourceCapabilities::EchoCancellation::ReadWrite);
</span><del>-    capabilities.setSampleRate(CapabilityValueOrRange(44100, 44100));
</del><ins>+    capabilities.setSampleRate(CapabilityValueOrRange(44100, 48000));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void MockRealtimeAudioSource::initializeSupportedConstraints(RealtimeMediaSourceSupportedConstraints&amp; supportedConstraints)
</span><span class="lines">@@ -103,6 +103,9 @@
</span><span class="cx"> 
</span><span class="cx"> void MockRealtimeAudioSource::startProducingData()
</span><span class="cx"> {
</span><ins>+    if (!sampleRate())
+        setSampleRate(!deviceIndex() ? 44100 : 48000);
+
</ins><span class="cx">     MockRealtimeMediaSource::startProducingData();
</span><span class="cx"> 
</span><span class="cx">     m_startTime = monotonicallyIncreasingTime();
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmockMockRealtimeMediaSourcecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -44,52 +44,37 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-const AtomicString&amp; MockRealtimeMediaSource::mockAudioSourcePersistentID()
</del><ins>+Vector&lt;CaptureDevice&gt;&amp; MockRealtimeMediaSource::audioDevices()
</ins><span class="cx"> {
</span><del>-    static NeverDestroyed&lt;AtomicString&gt; id(&quot;239c24b1-2b15-11e3-8224-0800200c9a66&quot;, AtomicString::ConstructFromLiteral);
-    return id;
</del><ins>+    static NeverDestroyed&lt;Vector&lt;CaptureDevice&gt;&gt; info;
+    if (!info.get().size()) {
+        info.get().append(CaptureDevice(&quot;239c24b0-2b15-11e3-8224-0800200c9a66&quot;, CaptureDevice::DeviceType::Audio, &quot;Mock audio device 1&quot;));
+        info.get().append(CaptureDevice(&quot;239c24b1-2b15-11e3-8224-0800200c9a66&quot;, CaptureDevice::DeviceType::Audio, &quot;Mock audio device 2&quot;));
+    }
+    return info;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-const AtomicString&amp; MockRealtimeMediaSource::mockVideoSourcePersistentID()
</del><ins>+Vector&lt;CaptureDevice&gt;&amp; MockRealtimeMediaSource::videoDevices()
</ins><span class="cx"> {
</span><del>-    static NeverDestroyed&lt;AtomicString&gt; id(&quot;239c24b0-2b15-11e3-8224-0800200c9a66&quot;, AtomicString::ConstructFromLiteral);
-    return id;
</del><ins>+    static NeverDestroyed&lt;Vector&lt;CaptureDevice&gt;&gt; info;
+    if (!info.get().size()) {
+        info.get().append(CaptureDevice(&quot;239c24b2-2b15-11e3-8224-0800200c9a66&quot;, CaptureDevice::DeviceType::Video, &quot;Mock video device 1&quot;));
+        info.get().append(CaptureDevice(&quot;239c24b3-2b15-11e3-8224-0800200c9a66&quot;, CaptureDevice::DeviceType::Video, &quot;Mock video device 2&quot;));
+    }
+    return info;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-const AtomicString&amp; MockRealtimeMediaSource::mockAudioSourceName()
-{
-    static NeverDestroyed&lt;AtomicString&gt; name(&quot;Mock audio device&quot;, AtomicString::ConstructFromLiteral);
-    return name;
-}
-
-const AtomicString&amp; MockRealtimeMediaSource::mockVideoSourceName()
-{
-    static NeverDestroyed&lt;AtomicString&gt; name(&quot;Mock video device&quot;, AtomicString::ConstructFromLiteral);
-    return name;
-}
-
-CaptureDevice MockRealtimeMediaSource::audioDeviceInfo()
-{
-    static NeverDestroyed&lt;CaptureDevice&gt; deviceInfo(mockAudioSourcePersistentID(), CaptureDevice::DeviceType::Audio, mockAudioSourceName(), &quot;&quot;);
-    return deviceInfo;
-}
-
-CaptureDevice MockRealtimeMediaSource::videoDeviceInfo()
-{
-    static NeverDestroyed&lt;CaptureDevice&gt; deviceInfo(mockVideoSourcePersistentID(), CaptureDevice::DeviceType::Video, mockVideoSourceName(), &quot;&quot;);
-    return deviceInfo;
-}
-
-
</del><span class="cx"> MockRealtimeMediaSource::MockRealtimeMediaSource(const String&amp; id, RealtimeMediaSource::Type type, const String&amp; name)
</span><span class="cx">     : BaseRealtimeMediaSourceClass(id, type, name)
</span><span class="cx"> {
</span><span class="cx">     switch (type) {
</span><span class="cx">     case RealtimeMediaSource::Type::Audio:
</span><del>-        setPersistentID(mockAudioSourcePersistentID());
</del><ins>+        m_deviceIndex = name == audioDevices()[0].label() ? 0 : 1;
+        setPersistentID(audioDevices()[m_deviceIndex].persistentId());
</ins><span class="cx">         return;
</span><span class="cx">     case RealtimeMediaSource::Type::Video:
</span><del>-        setPersistentID(mockVideoSourcePersistentID());
</del><ins>+        m_deviceIndex = name == videoDevices()[0].label() ? 0 : 1;
+        setPersistentID(videoDevices()[m_deviceIndex].persistentId());
</ins><span class="cx">         return;
</span><span class="cx">     case RealtimeMediaSource::Type::None:
</span><span class="cx">         ASSERT_NOT_REACHED();
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmockMockRealtimeMediaSourceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.h (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.h        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.h        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -53,15 +53,9 @@
</span><span class="cx"> public:
</span><span class="cx">     virtual ~MockRealtimeMediaSource() { }
</span><span class="cx"> 
</span><del>-    static const AtomicString&amp; mockAudioSourcePersistentID();
-    static const AtomicString&amp; mockAudioSourceName();
</del><ins>+    static Vector&lt;CaptureDevice&gt;&amp; audioDevices();
+    static Vector&lt;CaptureDevice&gt;&amp; videoDevices();
</ins><span class="cx"> 
</span><del>-    static const AtomicString&amp; mockVideoSourcePersistentID();
-    static const AtomicString&amp; mockVideoSourceName();
-
-    static CaptureDevice audioDeviceInfo();
-    static CaptureDevice videoDeviceInfo();
-
</del><span class="cx"> protected:
</span><span class="cx">     MockRealtimeMediaSource(const String&amp; id, Type, const String&amp; name);
</span><span class="cx"> 
</span><span class="lines">@@ -78,6 +72,8 @@
</span><span class="cx">     MediaConstraints&amp; constraints() { return *m_constraints.get(); }
</span><span class="cx">     RealtimeMediaSourceSupportedConstraints&amp; supportedConstraints();
</span><span class="cx"> 
</span><ins>+    unsigned deviceIndex() { return m_deviceIndex; }
+
</ins><span class="cx"> private:
</span><span class="cx">     void initializeCapabilities();
</span><span class="cx">     void initializeSettings();
</span><span class="lines">@@ -87,6 +83,7 @@
</span><span class="cx">     RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
</span><span class="cx">     RefPtr&lt;RealtimeMediaSourceCapabilities&gt; m_capabilities;
</span><span class="cx">     RefPtr&lt;MediaConstraints&gt; m_constraints;
</span><ins>+    unsigned m_deviceIndex { 0 };
</ins><span class="cx">     bool m_isProducingData { false };
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmockMockRealtimeMediaSourceCentercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -73,26 +73,31 @@
</span><span class="cx">     String invalidConstraint;
</span><span class="cx"> 
</span><span class="cx">     if (audioConstraints.isValid()) {
</span><del>-        auto audioSource = MockRealtimeAudioSource::create(MockRealtimeMediaSource::mockAudioSourceName(), nullptr);
-        if (!audioSource-&gt;supportsConstraints(audioConstraints, invalidConstraint)) {
-            if (invalidHandler)
-                invalidHandler(invalidConstraint);
-            return;
</del><ins>+        auto&amp; devices = MockRealtimeMediaSource::audioDevices();
+        for (size_t i = 0; i &lt; devices.size(); i++) {
+            auto&amp; device = devices[i];
+            auto audioSource = MockRealtimeAudioSource::create(device.label(), nullptr);
+            if (!audioSource-&gt;supportsConstraints(audioConstraints, invalidConstraint)) {
+                if (invalidHandler)
+                    invalidHandler(invalidConstraint);
+                return;
+            }
+            audioSourceIds.append(device.persistentId());
</ins><span class="cx">         }
</span><del>-
-        audioSourceIds.append(MockRealtimeMediaSource::mockAudioSourcePersistentID());
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (videoConstraints.isValid()) {
</span><del>-        auto videoSource = MockRealtimeVideoSource::create(MockRealtimeMediaSource::mockVideoSourceName(), nullptr);
-        if (!videoSource-&gt;supportsConstraints(videoConstraints, invalidConstraint)) {
-            if (invalidHandler)
-                invalidHandler(invalidConstraint);
-            return;
</del><ins>+        auto&amp; devices = MockRealtimeMediaSource::videoDevices();
+        for (size_t i = 0; i &lt; devices.size(); i++) {
+            auto&amp; device = devices[i];
+            auto videoSource = MockRealtimeVideoSource::create(device.label(), nullptr);
+            if (!videoSource-&gt;supportsConstraints(videoConstraints, invalidConstraint)) {
+                if (invalidHandler)
+                    invalidHandler(invalidConstraint);
+                return;
+            }
+            videoSourceIds.append(device.persistentId());
</ins><span class="cx">         }
</span><del>-
-
-        videoSourceIds.append(MockRealtimeMediaSource::mockVideoSourcePersistentID());
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     validHandler(WTFMove(audioSourceIds), WTFMove(videoSourceIds));
</span><span class="lines">@@ -103,16 +108,30 @@
</span><span class="cx">     Vector&lt;Ref&lt;RealtimeMediaSource&gt;&gt; audioSources;
</span><span class="cx">     Vector&lt;Ref&lt;RealtimeMediaSource&gt;&gt; videoSources;
</span><span class="cx"> 
</span><del>-    if (audioDeviceID == MockRealtimeMediaSource::mockAudioSourcePersistentID()) {
-        auto source = MockRealtimeAudioSource::create(MockRealtimeMediaSource::mockAudioSourceName(), audioConstraints);
-        if (source)
-            audioSources.append(source.releaseNonNull());
</del><ins>+    if (!audioDeviceID.isEmpty()) {
+        auto&amp; audioDevices = MockRealtimeMediaSource::audioDevices();
+        if (audioDeviceID == audioDevices[0].persistentId()) {
+            auto source = MockRealtimeAudioSource::create(audioDevices[0].label(), audioConstraints);
+            if (source)
+                audioSources.append(source.releaseNonNull());
+        } else if (audioDeviceID == audioDevices[1].persistentId()) {
+            auto source = MockRealtimeAudioSource::create(audioDevices[1].label(), audioConstraints);
+            if (source)
+                audioSources.append(source.releaseNonNull());
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (videoDeviceID == MockRealtimeMediaSource::mockVideoSourcePersistentID()) {
-        auto source = MockRealtimeVideoSource::create(MockRealtimeMediaSource::mockVideoSourceName(), videoConstraints);
-        if (source)
-            videoSources.append(source.releaseNonNull());
</del><ins>+    if (!videoDeviceID.isEmpty()) {
+        auto&amp; videoDevices = MockRealtimeMediaSource::videoDevices();
+        if (videoDeviceID == videoDevices[0].persistentId()) {
+            auto source = MockRealtimeVideoSource::create(videoDevices[0].label(), videoConstraints);
+            if (source)
+                videoSources.append(source.releaseNonNull());
+        } else if (videoDeviceID == videoDevices[1].persistentId()) {
+            auto source = MockRealtimeVideoSource::create(videoDevices[1].label(), videoConstraints);
+            if (source)
+                videoSources.append(source.releaseNonNull());
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (videoSources.isEmpty() &amp;&amp; audioSources.isEmpty())
</span><span class="lines">@@ -125,8 +144,8 @@
</span><span class="cx"> {
</span><span class="cx">     Vector&lt;CaptureDevice&gt; sources;
</span><span class="cx"> 
</span><del>-    sources.append(MockRealtimeMediaSource::audioDeviceInfo());
-    sources.append(MockRealtimeMediaSource::videoDeviceInfo());
</del><ins>+    sources.appendVector(MockRealtimeMediaSource::audioDevices());
+    sources.appendVector(MockRealtimeMediaSource::videoDevices());
</ins><span class="cx"> 
</span><span class="cx">     return sources;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmockMockRealtimeVideoSourcecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp (214177 => 214178)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp        2017-03-20 17:51:45 UTC (rev 214177)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp        2017-03-20 17:55:20 UTC (rev 214178)
</span><span class="lines">@@ -85,7 +85,8 @@
</span><span class="cx">     : MockRealtimeMediaSource(createCanonicalUUIDString(), RealtimeMediaSource::Type::Video, name)
</span><span class="cx">     , m_timer(RunLoop::current(), this, &amp;MockRealtimeVideoSource::generateFrame)
</span><span class="cx"> {
</span><del>-    setFrameRate(30);
</del><ins>+    setFrameRate(!deviceIndex() ? 30 : 15);
+    setFacingMode(!deviceIndex() ? RealtimeMediaSourceSettings::User : RealtimeMediaSourceSettings::Environment);
</ins><span class="cx">     m_dashWidths.reserveInitialCapacity(2);
</span><span class="cx">     m_dashWidths.uncheckedAppend(6);
</span><span class="cx">     m_dashWidths.uncheckedAppend(6);
</span></span></pre>
</div>
</div>

</body>
</html>