<!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>[213080] 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/213080">213080</a></dd>
<dt>Author</dt> <dd>jer.noble@apple.com</dd>
<dt>Date</dt> <dd>2017-02-27 10:22:49 -0800 (Mon, 27 Feb 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>[WebRTC] Fix remote audio rendering
https://bugs.webkit.org/show_bug.cgi?id=168898

Reviewed by Eric Carlson.

Source/WebCore:

Test: webrtc/audio-peer-connection-webaudio.html

Fix MediaStreamAudioSourceNode by not bailing out early if the input sample rate doesn't match
the AudioContext's sample rate; there's code in setFormat() to do the sample rate conversion
correctly.

* Modules/webaudio/MediaStreamAudioSourceNode.cpp:
(WebCore::MediaStreamAudioSourceNode::setFormat):

Fix AudioSampleBufferList by making the AudioConverter input proc a free function, and passing
its refCon a struct containing only the information it needs to perform its task. Because the
conversion may result in a different number of output samples than input ones, just ask to
generate the entire capacity of the scratch buffer, and signal that the input buffer was fully
converted with a special return value.

* platform/audio/mac/AudioSampleBufferList.cpp:
(WebCore::audioConverterFromABLCallback):
(WebCore::AudioSampleBufferList::copyFrom):
(WebCore::AudioSampleBufferList::convertInput): Deleted.
(WebCore::AudioSampleBufferList::audioConverterCallback): Deleted.
* platform/audio/mac/AudioSampleBufferList.h:

Fix AudioSampleDataSource by updating both the sampleCount and the sampleTime after doing
a sample rate conversion to take into account that both the number of samples may have changed,
as well as the timeScale of the sampleTime. This may result in small off-by-one rounding errors
due to the sample rate conversion of sampleTime, so remember what the next expected sampleTime
should be, and correct sampleTime if it is indeed off-by-one. If the pull operation has gotten
ahead of the push operation, delay the next pull by the empty amount by rolling back the
m_outputSampleOffset. Introduce the same offset behavior during pull operations.

* platform/audio/mac/AudioSampleDataSource.h:
* platform/audio/mac/AudioSampleDataSource.mm:
(WebCore::AudioSampleDataSource::pushSamplesInternal):
(WebCore::AudioSampleDataSource::pullSamplesInternal):
(WebCore::AudioSampleDataSource::pullAvalaibleSamplesAsChunks):

Fix MediaPlayerPrivateMediaStreamAVFObjC by obeying the m_muted property.

* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::setVolume):
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::setMuted):

Fix LibWebRTCAudioModule by sleeping for the correct amount after emitting frames. Previously,
LibWebRTCAudioModule would sleep for a fixed amount of time, which meant it would get slowly out
of sync when emitting frames took a non-zero amount of time. Now, the amount of time before the
next cycle starts is correctly calculated, and then LibWebRTCAudioModule sleeps for a dynamic amount
of time in order to wake up correctly at the beginning of the next cycle.

* platform/mediastream/libwebrtc/LibWebRTCAudioModule.cpp:
(WebCore::LibWebRTCAudioModule::StartPlayoutOnAudioThread):

Fix AudioTrackPrivateMediaStreamCocoa by just using the output unit's preferred format
description (with the current system sample rate), rather than whatever is the current
input description.

* platform/mediastream/mac/AudioTrackPrivateMediaStreamCocoa.cpp:
(WebCore::AudioTrackPrivateMediaStreamCocoa::createAudioUnit):
(WebCore::AudioTrackPrivateMediaStreamCocoa::audioSamplesAvailable):
* platform/mediastream/mac/AudioTrackPrivateMediaStreamCocoa.h:

Fix RealtimeIncomingAudioSource by actually creating an AudioSourceProvider when asked.

* platform/mediastream/mac/RealtimeIncomingAudioSource.cpp:
(WebCore::RealtimeIncomingAudioSource::OnData):
(WebCore::RealtimeIncomingAudioSource::audioSourceProvider):
* platform/mediastream/mac/RealtimeIncomingAudioSource.h:

Fix RealtimeOutgoingAudioSource by using the outgoing format description rather than the
incoming one to determine the sample rate, channel count, sample byte size, etc., to use
when delivering data upstream to libWebRTC.

* platform/mediastream/mac/RealtimeOutgoingAudioSource.cpp:
(WebCore::RealtimeOutgoingAudioSource::audioSamplesAvailable):
(WebCore::RealtimeOutgoingAudioSource::pullAudioData):
* platform/mediastream/mac/RealtimeOutgoingAudioSource.h:

Fix WebAudioSourceProviderAVFObjC by using a AudioSampleDataSource to do format and sample
rate conversion rather than trying to duplicate all that code and use a CARingBuffer and
AudioConverter directly.

* platform/mediastream/mac/WebAudioSourceProviderAVFObjC.h:
* platform/mediastream/mac/WebAudioSourceProviderAVFObjC.mm:
(WebCore::WebAudioSourceProviderAVFObjC::~WebAudioSourceProviderAVFObjC):
(WebCore::WebAudioSourceProviderAVFObjC::provideInput):
(WebCore::WebAudioSourceProviderAVFObjC::prepare):
(WebCore::WebAudioSourceProviderAVFObjC::unprepare):
(WebCore::WebAudioSourceProviderAVFObjC::audioSamplesAvailable):

Fix the MockLibWebRTCAudioTrack by passing along the AddSink() sink to its AudioSourceInterface,
allowing the RealtimeOutgoingAudioSource to push data into the libWebRTC network stack. Also,
make sure m_enabled is initialized to a good value.

* testing/MockLibWebRTCPeerConnection.h:

LayoutTests:

* webrtc/audio-peer-connection-webaudio-expected.txt: Added.
* webrtc/audio-peer-connection-webaudio.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModuleswebaudioMediaStreamAudioSourceNodecpp">trunk/Source/WebCore/Modules/webaudio/MediaStreamAudioSourceNode.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformaudiomacAudioSampleBufferListcpp">trunk/Source/WebCore/platform/audio/mac/AudioSampleBufferList.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformaudiomacAudioSampleBufferListh">trunk/Source/WebCore/platform/audio/mac/AudioSampleBufferList.h</a></li>
<li><a href="#trunkSourceWebCoreplatformaudiomacAudioSampleDataSourceh">trunk/Source/WebCore/platform/audio/mac/AudioSampleDataSource.h</a></li>
<li><a href="#trunkSourceWebCoreplatformaudiomacAudioSampleDataSourcemm">trunk/Source/WebCore/platform/audio/mac/AudioSampleDataSource.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsavfoundationobjcMediaPlayerPrivateMediaStreamAVFObjCmm">trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreamlibwebrtcLibWebRTCAudioModulecpp">trunk/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCAudioModule.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacAudioTrackPrivateMediaStreamCocoacpp">trunk/Source/WebCore/platform/mediastream/mac/AudioTrackPrivateMediaStreamCocoa.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacAudioTrackPrivateMediaStreamCocoah">trunk/Source/WebCore/platform/mediastream/mac/AudioTrackPrivateMediaStreamCocoa.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacRealtimeIncomingAudioSourcecpp">trunk/Source/WebCore/platform/mediastream/mac/RealtimeIncomingAudioSource.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacRealtimeIncomingAudioSourceh">trunk/Source/WebCore/platform/mediastream/mac/RealtimeIncomingAudioSource.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacRealtimeOutgoingAudioSourcecpp">trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingAudioSource.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacRealtimeOutgoingAudioSourceh">trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingAudioSource.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacWebAudioSourceProviderAVFObjCh">trunk/Source/WebCore/platform/mediastream/mac/WebAudioSourceProviderAVFObjC.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmediastreammacWebAudioSourceProviderAVFObjCmm">trunk/Source/WebCore/platform/mediastream/mac/WebAudioSourceProviderAVFObjC.mm</a></li>
<li><a href="#trunkSourceWebCoretestingMockLibWebRTCPeerConnectionh">trunk/Source/WebCore/testing/MockLibWebRTCPeerConnection.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestswebrtcaudiopeerconnectionwebaudioexpectedtxt">trunk/LayoutTests/webrtc/audio-peer-connection-webaudio-expected.txt</a></li>
<li><a href="#trunkLayoutTestswebrtcaudiopeerconnectionwebaudiohtml">trunk/LayoutTests/webrtc/audio-peer-connection-webaudio.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/LayoutTests/ChangeLog        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2017-02-27  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        [WebRTC] Fix remote audio rendering
+        https://bugs.webkit.org/show_bug.cgi?id=168898
+
+        Reviewed by Eric Carlson.
+
+        * webrtc/audio-peer-connection-webaudio-expected.txt: Added.
+        * webrtc/audio-peer-connection-webaudio.html: Added.
+
</ins><span class="cx"> 2017-02-27  Fujii Hironori  &lt;Hironori.Fujii@sony.com&gt;
</span><span class="cx"> 
</span><span class="cx">         compositing/transitions/transform-on-large-layer.html : ImageDiff produced stderr output
</span></span></pre></div>
<a id="trunkLayoutTestswebrtcaudiopeerconnectionwebaudioexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/webrtc/audio-peer-connection-webaudio-expected.txt (0 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/webrtc/audio-peer-connection-webaudio-expected.txt                                (rev 0)
+++ trunk/LayoutTests/webrtc/audio-peer-connection-webaudio-expected.txt        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -0,0 +1,3 @@
</span><ins>+
+PASS Basic audio playback through a peer connection 
+
</ins></span></pre></div>
<a id="trunkLayoutTestswebrtcaudiopeerconnectionwebaudiohtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/webrtc/audio-peer-connection-webaudio.html (0 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/webrtc/audio-peer-connection-webaudio.html                                (rev 0)
+++ trunk/LayoutTests/webrtc/audio-peer-connection-webaudio.html        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -0,0 +1,84 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+    &lt;meta charset=&quot;utf-8&quot;&gt;
+    &lt;title&gt;Testing local audio capture playback causes &quot;playing&quot; event to fire&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;script src =&quot;routines.js&quot;&gt;&lt;/script&gt;
+    &lt;script&gt;
+    var test = async_test(() =&gt; {
+        if (window.internals)
+            internals.useMockRTCPeerConnectionFactory(&quot;TwoRealPeerConnections&quot;);
+
+        if (window.testRunner)
+            testRunner.setUserMediaPermission(true);
+
+        var heardHum = false;
+        var heardBop = false;
+        var heardBip = false;
+
+        navigator.mediaDevices.getUserMedia({audio: true}).then((stream) =&gt; {
+            createConnections((firstConnection) =&gt; {
+                firstConnection.addStream(stream);
+            }, (secondConnection) =&gt; {
+                secondConnection.onaddstream = (streamEvent) =&gt; { 
+                    var context = new webkitAudioContext();
+                    var sourceNode = context.createMediaStreamSource(streamEvent.stream);
+                    var analyser = context.createAnalyser();
+                    var gain = context.createGain();
+
+                    analyser.fftSize = 2048;
+                    analyser.smoothingTimeConstant = 0;
+                    analyser.minDecibels = -100;
+                    analyser.maxDecibels = 0;
+                    gain.gain.value = 0;
+
+                    sourceNode.connect(analyser);
+                    analyser.connect(gain);
+                    gain.connect(context.destination);
+
+                    function analyse() {
+                        var freqDomain = new Uint8Array(analyser.frequencyBinCount);
+                        analyser.getByteFrequencyData(freqDomain);
+
+                        var hasFrequency = expectedFrequency =&gt; {
+                            var bin = Math.floor(expectedFrequency * analyser.fftSize / context.sampleRate);
+                            return bin &lt; freqDomain.length &amp;&amp; freqDomain[bin] &gt;= 150;
+                        };
+
+                        if (!heardHum)
+                            heardHum = hasFrequency(150);
+
+                        if (!heardBip)
+                            heardBip = hasFrequency(1500);
+
+                        if (!heardBop)
+                            heardBop = hasFrequency(500);
+
+                        if (heardHum &amp;&amp; heardBip &amp;&amp; heardBop)
+                            done();
+                    };
+
+                    var done = () =&gt; {
+                        clearTimeout(timeout);
+                        clearInterval(interval);
+
+                        assert_true(heardHum);
+                        assert_true(heardBip);
+                        assert_true(heardBop);
+                        test.done();
+                    };
+
+                    var timeout = setTimeout(done, 3000);
+                    var interval = setInterval(analyse, 1000 / 30);
+                    analyse();
+                }
+            });
+        });
+    }, &quot;Basic audio playback through a peer connection&quot;);
+    &lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/ChangeLog        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -1,3 +1,104 @@
</span><ins>+2017-02-27  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        [WebRTC] Fix remote audio rendering
+        https://bugs.webkit.org/show_bug.cgi?id=168898
+
+        Reviewed by Eric Carlson.
+
+        Test: webrtc/audio-peer-connection-webaudio.html
+
+        Fix MediaStreamAudioSourceNode by not bailing out early if the input sample rate doesn't match
+        the AudioContext's sample rate; there's code in setFormat() to do the sample rate conversion
+        correctly.
+
+        * Modules/webaudio/MediaStreamAudioSourceNode.cpp:
+        (WebCore::MediaStreamAudioSourceNode::setFormat):
+
+        Fix AudioSampleBufferList by making the AudioConverter input proc a free function, and passing
+        its refCon a struct containing only the information it needs to perform its task. Because the
+        conversion may result in a different number of output samples than input ones, just ask to
+        generate the entire capacity of the scratch buffer, and signal that the input buffer was fully
+        converted with a special return value.
+
+        * platform/audio/mac/AudioSampleBufferList.cpp:
+        (WebCore::audioConverterFromABLCallback):
+        (WebCore::AudioSampleBufferList::copyFrom):
+        (WebCore::AudioSampleBufferList::convertInput): Deleted.
+        (WebCore::AudioSampleBufferList::audioConverterCallback): Deleted.
+        * platform/audio/mac/AudioSampleBufferList.h:
+
+        Fix AudioSampleDataSource by updating both the sampleCount and the sampleTime after doing
+        a sample rate conversion to take into account that both the number of samples may have changed,
+        as well as the timeScale of the sampleTime. This may result in small off-by-one rounding errors
+        due to the sample rate conversion of sampleTime, so remember what the next expected sampleTime
+        should be, and correct sampleTime if it is indeed off-by-one. If the pull operation has gotten
+        ahead of the push operation, delay the next pull by the empty amount by rolling back the
+        m_outputSampleOffset. Introduce the same offset behavior during pull operations.
+
+        * platform/audio/mac/AudioSampleDataSource.h:
+        * platform/audio/mac/AudioSampleDataSource.mm:
+        (WebCore::AudioSampleDataSource::pushSamplesInternal):
+        (WebCore::AudioSampleDataSource::pullSamplesInternal):
+        (WebCore::AudioSampleDataSource::pullAvalaibleSamplesAsChunks):
+
+        Fix MediaPlayerPrivateMediaStreamAVFObjC by obeying the m_muted property.
+
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm:
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::setVolume):
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::setMuted):
+
+        Fix LibWebRTCAudioModule by sleeping for the correct amount after emitting frames. Previously,
+        LibWebRTCAudioModule would sleep for a fixed amount of time, which meant it would get slowly out
+        of sync when emitting frames took a non-zero amount of time. Now, the amount of time before the
+        next cycle starts is correctly calculated, and then LibWebRTCAudioModule sleeps for a dynamic amount
+        of time in order to wake up correctly at the beginning of the next cycle.
+
+        * platform/mediastream/libwebrtc/LibWebRTCAudioModule.cpp:
+        (WebCore::LibWebRTCAudioModule::StartPlayoutOnAudioThread):
+
+        Fix AudioTrackPrivateMediaStreamCocoa by just using the output unit's preferred format
+        description (with the current system sample rate), rather than whatever is the current
+        input description.
+
+        * platform/mediastream/mac/AudioTrackPrivateMediaStreamCocoa.cpp:
+        (WebCore::AudioTrackPrivateMediaStreamCocoa::createAudioUnit):
+        (WebCore::AudioTrackPrivateMediaStreamCocoa::audioSamplesAvailable):
+        * platform/mediastream/mac/AudioTrackPrivateMediaStreamCocoa.h:
+
+        Fix RealtimeIncomingAudioSource by actually creating an AudioSourceProvider when asked.
+
+        * platform/mediastream/mac/RealtimeIncomingAudioSource.cpp:
+        (WebCore::RealtimeIncomingAudioSource::OnData):
+        (WebCore::RealtimeIncomingAudioSource::audioSourceProvider):
+        * platform/mediastream/mac/RealtimeIncomingAudioSource.h:
+
+        Fix RealtimeOutgoingAudioSource by using the outgoing format description rather than the
+        incoming one to determine the sample rate, channel count, sample byte size, etc., to use
+        when delivering data upstream to libWebRTC.
+
+        * platform/mediastream/mac/RealtimeOutgoingAudioSource.cpp:
+        (WebCore::RealtimeOutgoingAudioSource::audioSamplesAvailable):
+        (WebCore::RealtimeOutgoingAudioSource::pullAudioData):
+        * platform/mediastream/mac/RealtimeOutgoingAudioSource.h:
+
+        Fix WebAudioSourceProviderAVFObjC by using a AudioSampleDataSource to do format and sample
+        rate conversion rather than trying to duplicate all that code and use a CARingBuffer and 
+        AudioConverter directly.
+
+        * platform/mediastream/mac/WebAudioSourceProviderAVFObjC.h:
+        * platform/mediastream/mac/WebAudioSourceProviderAVFObjC.mm:
+        (WebCore::WebAudioSourceProviderAVFObjC::~WebAudioSourceProviderAVFObjC):
+        (WebCore::WebAudioSourceProviderAVFObjC::provideInput):
+        (WebCore::WebAudioSourceProviderAVFObjC::prepare):
+        (WebCore::WebAudioSourceProviderAVFObjC::unprepare):
+        (WebCore::WebAudioSourceProviderAVFObjC::audioSamplesAvailable):
+
+        Fix the MockLibWebRTCAudioTrack by passing along the AddSink() sink to its AudioSourceInterface,
+        allowing the RealtimeOutgoingAudioSource to push data into the libWebRTC network stack. Also,
+        make sure m_enabled is initialized to a good value.
+
+        * testing/MockLibWebRTCPeerConnection.h:
+
</ins><span class="cx"> 2017-02-21  Jer Noble  &lt;jer.noble@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         AudioSampleDataSource should not exclusively lock its read and write threads.
</span></span></pre></div>
<a id="trunkSourceWebCoreModuleswebaudioMediaStreamAudioSourceNodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/webaudio/MediaStreamAudioSourceNode.cpp (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/webaudio/MediaStreamAudioSourceNode.cpp        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/Modules/webaudio/MediaStreamAudioSourceNode.cpp        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -73,7 +73,7 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     // The sample-rate must be equal to the context's sample-rate.
</span><del>-    if (!numberOfChannels || numberOfChannels &gt; AudioContext::maxNumberOfChannels() || sourceSampleRate != sampleRate) {
</del><ins>+    if (!numberOfChannels || numberOfChannels &gt; AudioContext::maxNumberOfChannels()) {
</ins><span class="cx">         // process() will generate silence for these uninitialized values.
</span><span class="cx">         LOG(Media, &quot;MediaStreamAudioSourceNode::setFormat(%u, %f) - unhandled format change&quot;, static_cast&lt;unsigned&gt;(numberOfChannels), sourceSampleRate);
</span><span class="cx">         m_sourceNumberOfChannels = 0;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformaudiomacAudioSampleBufferListcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/audio/mac/AudioSampleBufferList.cpp (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/audio/mac/AudioSampleBufferList.cpp        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/platform/audio/mac/AudioSampleBufferList.cpp        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -218,43 +218,49 @@
</span><span class="cx">         memset(buffer.mBuffers[i].mData, 0, byteCount);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-OSStatus AudioSampleBufferList::convertInput(UInt32* ioNumberDataPackets, AudioBufferList* ioData)
</del><ins>+struct AudioConverterFromABLContext {
+    const AudioBufferList&amp; buffer;
+    size_t packetsAvailableToConvert;
+    size_t bytesPerPacket;
+};
+
+static const OSStatus kRanOutOfInputDataStatus = '!mor';
+
+static OSStatus audioConverterFromABLCallback(AudioConverterRef, UInt32* ioNumberDataPackets, AudioBufferList* ioData, AudioStreamPacketDescription**, void* inRefCon)
</ins><span class="cx"> {
</span><del>-    if (!ioNumberDataPackets || !ioData || !m_converterInputBuffer) {
-        LOG_ERROR(&quot;AudioSampleBufferList::reconfigureInput(%p) invalid input to AudioConverterInput&quot;, this);
</del><ins>+    if (!ioNumberDataPackets || !ioData || !inRefCon) {
+        LOG_ERROR(&quot;AudioSampleBufferList::audioConverterCallback() invalid input to AudioConverterInput&quot;);
</ins><span class="cx">         return kAudioConverterErr_UnspecifiedError;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    size_t packetCount = m_converterInputBuffer-&gt;mBuffers[0].mDataByteSize / m_converterInputBytesPerPacket;
-    if (*ioNumberDataPackets &gt; m_sampleCapacity) {
-        LOG_ERROR(&quot;AudioSampleBufferList::convertInput(%p) not enough internal storage: needed = %zu, available = %lu&quot;, this, (size_t)*ioNumberDataPackets, m_sampleCapacity);
-        return kAudioConverterErr_InvalidInputSize;
</del><ins>+    auto&amp; context = *static_cast&lt;AudioConverterFromABLContext*&gt;(inRefCon);
+    if (!context.packetsAvailableToConvert) {
+        *ioNumberDataPackets = 0;
+        return kRanOutOfInputDataStatus;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    *ioNumberDataPackets = static_cast&lt;UInt32&gt;(packetCount);
</del><ins>+    *ioNumberDataPackets = static_cast&lt;UInt32&gt;(context.packetsAvailableToConvert);
+
</ins><span class="cx">     for (uint32_t i = 0; i &lt; ioData-&gt;mNumberBuffers; ++i) {
</span><del>-        ioData-&gt;mBuffers[i].mData = m_converterInputBuffer-&gt;mBuffers[i].mData;
-        ioData-&gt;mBuffers[i].mDataByteSize = m_converterInputBuffer-&gt;mBuffers[i].mDataByteSize;
</del><ins>+        ioData-&gt;mBuffers[i].mData = context.buffer.mBuffers[i].mData;
+        ioData-&gt;mBuffers[i].mDataByteSize = context.packetsAvailableToConvert * context.bytesPerPacket;
</ins><span class="cx">     }
</span><ins>+    context.packetsAvailableToConvert = 0;
</ins><span class="cx"> 
</span><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-OSStatus AudioSampleBufferList::audioConverterCallback(AudioConverterRef, UInt32* ioNumberDataPackets, AudioBufferList* ioData, AudioStreamPacketDescription**, void* inRefCon)
</del><ins>+OSStatus AudioSampleBufferList::copyFrom(const AudioBufferList&amp; source, size_t frameCount, AudioConverterRef converter)
</ins><span class="cx"> {
</span><del>-    return static_cast&lt;AudioSampleBufferList*&gt;(inRefCon)-&gt;convertInput(ioNumberDataPackets, ioData);
-}
-
-OSStatus AudioSampleBufferList::copyFrom(const AudioBufferList&amp; source, AudioConverterRef converter)
-{
</del><span class="cx">     reset();
</span><span class="cx"> 
</span><span class="cx">     AudioStreamBasicDescription inputFormat;
</span><span class="cx">     UInt32 propertyDataSize = sizeof(inputFormat);
</span><span class="cx">     AudioConverterGetProperty(converter, kAudioConverterCurrentInputStreamDescription, &amp;propertyDataSize, &amp;inputFormat);
</span><del>-    m_converterInputBytesPerPacket = inputFormat.mBytesPerPacket;
-    SetForScope&lt;const AudioBufferList*&gt; scopedInputBuffer(m_converterInputBuffer, &amp;source);
</del><ins>+    ASSERT(frameCount &lt;= source.mBuffers[0].mDataByteSize / inputFormat.mBytesPerPacket);
</ins><span class="cx"> 
</span><ins>+    AudioConverterFromABLContext context { source, frameCount, inputFormat.mBytesPerPacket };
+
</ins><span class="cx"> #if !LOG_DISABLED
</span><span class="cx">     AudioStreamBasicDescription outputFormat;
</span><span class="cx">     propertyDataSize = sizeof(outputFormat);
</span><span class="lines">@@ -267,22 +273,22 @@
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    UInt32 samplesConverted = static_cast&lt;UInt32&gt;(m_sampleCapacity);
-    OSStatus err = AudioConverterFillComplexBuffer(converter, audioConverterCallback, this, &amp;samplesConverted, m_bufferList-&gt;list(), nullptr);
-    if (err) {
-        LOG_ERROR(&quot;AudioSampleBufferList::copyFrom(%p) AudioConverterFillComplexBuffer returned error %d (%.4s)&quot;, this, (int)err, (char*)&amp;err);
-        m_sampleCount = std::min(m_sampleCapacity, static_cast&lt;size_t&gt;(samplesConverted));
-        zero();
-        return err;
</del><ins>+    UInt32 samplesConverted = m_sampleCapacity;
+    OSStatus err = AudioConverterFillComplexBuffer(converter, audioConverterFromABLCallback, &amp;context, &amp;samplesConverted, m_bufferList-&gt;list(), nullptr);
+    if (!err || err == kRanOutOfInputDataStatus) {
+        m_sampleCount = samplesConverted;
+        return 0;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    m_sampleCount = samplesConverted;
-    return 0;
</del><ins>+    LOG_ERROR(&quot;AudioSampleBufferList::copyFrom(%p) AudioConverterFillComplexBuffer returned error %d (%.4s)&quot;, this, (int)err, (char*)&amp;err);
+    m_sampleCount = std::min(m_sampleCapacity, static_cast&lt;size_t&gt;(samplesConverted));
+    zero();
+    return err;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-OSStatus AudioSampleBufferList::copyFrom(AudioSampleBufferList&amp; source, AudioConverterRef converter)
</del><ins>+OSStatus AudioSampleBufferList::copyFrom(AudioSampleBufferList&amp; source, size_t frameCount, AudioConverterRef converter)
</ins><span class="cx"> {
</span><del>-    return copyFrom(source.bufferList(), converter);
</del><ins>+    return copyFrom(source.bufferList(), frameCount, converter);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> OSStatus AudioSampleBufferList::copyFrom(CARingBuffer&amp; ringBuffer, size_t sampleCount, uint64_t startFrame, CARingBuffer::FetchMode mode)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformaudiomacAudioSampleBufferListh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/audio/mac/AudioSampleBufferList.h (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/audio/mac/AudioSampleBufferList.h        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/platform/audio/mac/AudioSampleBufferList.h        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -51,8 +51,8 @@
</span><span class="cx">     void applyGain(float);
</span><span class="cx"> 
</span><span class="cx">     OSStatus copyFrom(const AudioSampleBufferList&amp;, size_t count = SIZE_MAX);
</span><del>-    OSStatus copyFrom(const AudioBufferList&amp;, AudioConverterRef);
-    OSStatus copyFrom(AudioSampleBufferList&amp;, AudioConverterRef);
</del><ins>+    OSStatus copyFrom(const AudioBufferList&amp;, size_t frameCount, AudioConverterRef);
+    OSStatus copyFrom(AudioSampleBufferList&amp;, size_t frameCount, AudioConverterRef);
</ins><span class="cx">     OSStatus copyFrom(CARingBuffer&amp;, size_t frameCount, uint64_t startFrame, CARingBuffer::FetchMode);
</span><span class="cx"> 
</span><span class="cx">     OSStatus mixFrom(const AudioSampleBufferList&amp;, size_t count = SIZE_MAX);
</span><span class="lines">@@ -78,14 +78,8 @@
</span><span class="cx"> protected:
</span><span class="cx">     AudioSampleBufferList(const CAAudioStreamDescription&amp;, size_t);
</span><span class="cx"> 
</span><del>-    static OSStatus audioConverterCallback(AudioConverterRef, UInt32*, AudioBufferList*, AudioStreamPacketDescription**, void*);
-    OSStatus convertInput(UInt32*, AudioBufferList*);
-
</del><span class="cx">     std::unique_ptr&lt;CAAudioStreamDescription&gt; m_internalFormat;
</span><span class="cx"> 
</span><del>-    const AudioBufferList* m_converterInputBuffer { nullptr };
-    uint32_t m_converterInputBytesPerPacket { 0 };
-
</del><span class="cx">     uint64_t m_timestamp { 0 };
</span><span class="cx">     double m_hostTime { -1 };
</span><span class="cx">     size_t m_sampleCount { 0 };
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformaudiomacAudioSampleDataSourceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/audio/mac/AudioSampleDataSource.h (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/audio/mac/AudioSampleDataSource.h        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/platform/audio/mac/AudioSampleDataSource.h        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -82,10 +82,12 @@
</span><span class="cx">     MediaTime hostTime() const;
</span><span class="cx"> 
</span><span class="cx">     uint64_t m_timeStamp { 0 };
</span><ins>+    uint64_t m_lastPushedSampleCount { 0 };
+    MediaTime m_expectedNextPushedSampleTime { MediaTime::invalidTime() };
</ins><span class="cx">     double m_hostTime { -1 };
</span><span class="cx"> 
</span><span class="cx">     MediaTime m_inputSampleOffset;
</span><del>-    uint64_t m_outputSampleOffset { 0 };
</del><ins>+    int64_t m_outputSampleOffset { 0 };
</ins><span class="cx"> 
</span><span class="cx">     AudioConverterRef m_converter;
</span><span class="cx">     RefPtr&lt;AudioSampleBufferList&gt; m_scratchBuffer;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformaudiomacAudioSampleDataSourcemm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/audio/mac/AudioSampleDataSource.mm (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/audio/mac/AudioSampleDataSource.mm        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/platform/audio/mac/AudioSampleDataSource.mm        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -141,24 +141,27 @@
</span><span class="cx"> 
</span><span class="cx"> void AudioSampleDataSource::pushSamplesInternal(const AudioBufferList&amp; bufferList, const MediaTime&amp; presentationTime, size_t sampleCount)
</span><span class="cx"> {
</span><ins>+    MediaTime sampleTime = presentationTime;
+
</ins><span class="cx">     const AudioBufferList* sampleBufferList;
</span><span class="cx">     if (m_converter) {
</span><span class="cx">         m_scratchBuffer-&gt;reset();
</span><del>-        OSStatus err = m_scratchBuffer-&gt;copyFrom(bufferList, m_converter);
</del><ins>+        OSStatus err = m_scratchBuffer-&gt;copyFrom(bufferList, sampleCount, m_converter);
</ins><span class="cx">         if (err)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         sampleBufferList = m_scratchBuffer-&gt;bufferList().list();
</span><ins>+        sampleCount = m_scratchBuffer-&gt;sampleCount();
+        sampleTime = presentationTime.toTimeScale(m_outputDescription-&gt;sampleRate(), MediaTime::RoundingFlags::TowardZero);
</ins><span class="cx">     } else
</span><span class="cx">         sampleBufferList = &amp;bufferList;
</span><span class="cx"> 
</span><del>-    MediaTime sampleTime = presentationTime;
</del><ins>+    if (m_expectedNextPushedSampleTime.isValid() &amp;&amp; abs(m_expectedNextPushedSampleTime - sampleTime).timeValue() == 1)
+        sampleTime = m_expectedNextPushedSampleTime;
+    m_expectedNextPushedSampleTime = sampleTime + MediaTime(sampleCount, sampleTime.timeScale());
+
</ins><span class="cx">     if (m_inputSampleOffset == MediaTime::invalidTime()) {
</span><span class="cx">         m_inputSampleOffset = MediaTime(1 - sampleTime.timeValue(), sampleTime.timeScale());
</span><del>-        if (m_inputSampleOffset.timeScale() != sampleTime.timeScale()) {
-            // FIXME: It should be possible to do this without calling CMTimeConvertScale.
-            m_inputSampleOffset = toMediaTime(CMTimeConvertScale(toCMTime(m_inputSampleOffset), sampleTime.timeScale(), kCMTimeRoundingMethod_Default));
-        }
</del><span class="cx">         LOG(MediaCaptureSamples, &quot;@@ pushSamples: input sample offset is %lld, m_maximumSampleCount = %zu&quot;, m_inputSampleOffset.timeValue(), m_maximumSampleCount);
</span><span class="cx">     }
</span><span class="cx">     sampleTime += m_inputSampleOffset;
</span><span class="lines">@@ -267,11 +270,9 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">         if (framesAvailable &lt; sampleCount) {
</span><del>-            const double twentyMS = .02;
-            double sampleRate = m_outputDescription-&gt;sampleRate();
-            auto delta = static_cast&lt;int64_t&gt;(timeStamp) - endFrame;
-            if (delta &gt; 0 &amp;&amp; delta &lt; sampleRate * twentyMS)
-                m_outputSampleOffset -= delta;
</del><ins>+            int64_t delta = static_cast&lt;int64_t&gt;(timeStamp) - static_cast&lt;int64_t&gt;(endFrame);
+            if (delta &gt; 0)
+                m_outputSampleOffset -= std::min&lt;int64_t&gt;(delta, sampleCount);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (!framesAvailable) {
</span><span class="lines">@@ -300,8 +301,15 @@
</span><span class="cx">     uint64_t startFrame = 0;
</span><span class="cx">     uint64_t endFrame = 0;
</span><span class="cx">     m_ringBuffer-&gt;getCurrentFrameBounds(startFrame, endFrame);
</span><ins>+    if (m_transitioningFromPaused) {
+        m_outputSampleOffset = timeStamp + (endFrame - sampleCountPerChunk);
+        m_transitioningFromPaused = false;
+    }
+
+    timeStamp += m_outputSampleOffset;
+
</ins><span class="cx">     if (timeStamp &lt; startFrame)
</span><del>-        return false;
</del><ins>+        timeStamp = startFrame;
</ins><span class="cx"> 
</span><span class="cx">     startFrame = timeStamp;
</span><span class="cx">     while (endFrame - startFrame &gt;= sampleCountPerChunk) {
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcMediaPlayerPrivateMediaStreamAVFObjCmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -571,7 +571,7 @@
</span><span class="cx"> 
</span><span class="cx">     m_volume = volume;
</span><span class="cx">     for (const auto&amp; track : m_audioTrackMap.values())
</span><del>-        track-&gt;setVolume(m_volume);
</del><ins>+        track-&gt;setVolume(m_muted ? 0 : m_volume);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void MediaPlayerPrivateMediaStreamAVFObjC::setMuted(bool muted)
</span><span class="lines">@@ -582,6 +582,8 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     m_muted = muted;
</span><ins>+    for (const auto&amp; track : m_audioTrackMap.values())
+        track-&gt;setVolume(m_muted ? 0 : m_volume);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool MediaPlayerPrivateMediaStreamAVFObjC::hasVideo() const
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreamlibwebrtcLibWebRTCAudioModulecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCAudioModule.cpp (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCAudioModule.cpp        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/platform/mediastream/libwebrtc/LibWebRTCAudioModule.cpp        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -28,6 +28,8 @@
</span><span class="cx"> 
</span><span class="cx"> #if USE(LIBWEBRTC)
</span><span class="cx"> 
</span><ins>+#include &lt;wtf/CurrentTime.h&gt;
+
</ins><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> LibWebRTCAudioModule::LibWebRTCAudioModule()
</span><span class="lines">@@ -75,9 +77,13 @@
</span><span class="cx"> 
</span><span class="cx"> void LibWebRTCAudioModule::StartPlayoutOnAudioThread()
</span><span class="cx"> {
</span><ins>+    double startTime = WTF::monotonicallyIncreasingTimeMS();
</ins><span class="cx">     while (true) {
</span><span class="cx">         PollFromSource();
</span><del>-        m_audioTaskRunner-&gt;SleepMs(pollInterval);
</del><ins>+
+        double now = WTF::monotonicallyIncreasingTimeMS();
+        double sleepFor = pollInterval - remainder(now - startTime, pollInterval);
+        m_audioTaskRunner-&gt;SleepMs(sleepFor);
</ins><span class="cx">         if (!m_isPlaying)
</span><span class="cx">             return;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacAudioTrackPrivateMediaStreamCocoacpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/AudioTrackPrivateMediaStreamCocoa.cpp (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/AudioTrackPrivateMediaStreamCocoa.cpp        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/platform/mediastream/mac/AudioTrackPrivateMediaStreamCocoa.cpp        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -102,7 +102,7 @@
</span><span class="cx">         m_dataSource-&gt;setVolume(m_volume);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-AudioComponentInstance AudioTrackPrivateMediaStreamCocoa::createAudioUnit(const CAAudioStreamDescription&amp; inputDescription, CAAudioStreamDescription&amp; outputDescription)
</del><ins>+AudioComponentInstance AudioTrackPrivateMediaStreamCocoa::createAudioUnit(CAAudioStreamDescription&amp; outputDescription)
</ins><span class="cx"> {
</span><span class="cx">     AudioComponentInstance remoteIOUnit { nullptr };
</span><span class="cx"> 
</span><span class="lines">@@ -142,14 +142,13 @@
</span><span class="cx">         return nullptr;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    UInt32 size = sizeof(outputDescription);
-    err  = AudioUnitGetProperty(remoteIOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &amp;outputDescription, &amp;size);
</del><ins>+    UInt32 size = sizeof(outputDescription.streamDescription());
+    err  = AudioUnitGetProperty(remoteIOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &amp;outputDescription.streamDescription(), &amp;size);
</ins><span class="cx">     if (err) {
</span><span class="cx">         LOG(Media, &quot;AudioTrackPrivateMediaStreamCocoa::createAudioUnits(%p) unable to get input stream format, error %d (%.4s)&quot;, this, (int)err, (char*)&amp;err);
</span><span class="cx">         return nullptr;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    outputDescription = inputDescription;
</del><span class="cx">     outputDescription.streamDescription().mSampleRate = AudioSession::sharedSession().sampleRate();
</span><span class="cx"> 
</span><span class="cx">     err = AudioUnitSetProperty(remoteIOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &amp;outputDescription.streamDescription(), sizeof(outputDescription.streamDescription()));
</span><span class="lines">@@ -190,7 +189,7 @@
</span><span class="cx">         CAAudioStreamDescription inputDescription = toCAAudioStreamDescription(description);
</span><span class="cx">         CAAudioStreamDescription outputDescription;
</span><span class="cx"> 
</span><del>-        auto remoteIOUnit = createAudioUnit(inputDescription, outputDescription);
</del><ins>+        auto remoteIOUnit = createAudioUnit(outputDescription);
</ins><span class="cx">         if (!remoteIOUnit)
</span><span class="cx">             return;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacAudioTrackPrivateMediaStreamCocoah"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/AudioTrackPrivateMediaStreamCocoa.h (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/AudioTrackPrivateMediaStreamCocoa.h        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/platform/mediastream/mac/AudioTrackPrivateMediaStreamCocoa.h        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -66,7 +66,7 @@
</span><span class="cx">     static OSStatus inputProc(void*, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32 inBusNumber, UInt32 numberOfFrames, AudioBufferList*);
</span><span class="cx">     OSStatus render(UInt32 sampleCount, AudioBufferList&amp;, UInt32 inBusNumber, const AudioTimeStamp&amp;, AudioUnitRenderActionFlags&amp;);
</span><span class="cx"> 
</span><del>-    AudioComponentInstance createAudioUnit(const CAAudioStreamDescription&amp; inputDescription, CAAudioStreamDescription&amp; outputDescription);
</del><ins>+    AudioComponentInstance createAudioUnit(CAAudioStreamDescription&amp;);
</ins><span class="cx">     void cleanup();
</span><span class="cx">     void zeroBufferList(AudioBufferList&amp;, size_t);
</span><span class="cx">     void playInternal();
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacRealtimeIncomingAudioSourcecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/RealtimeIncomingAudioSource.cpp (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/RealtimeIncomingAudioSource.cpp        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/platform/mediastream/mac/RealtimeIncomingAudioSource.cpp        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -88,7 +88,12 @@
</span><span class="cx">     auto mediaTime = toMediaTime(startTime);
</span><span class="cx">     m_numberOfFrames += numberOfFrames;
</span><span class="cx"> 
</span><del>-    m_streamFormat = streamDescription(sampleRate, numberOfChannels);
</del><ins>+    AudioStreamBasicDescription newDescription = streamDescription(sampleRate, numberOfChannels);
+    if (newDescription != m_streamFormat) {
+        m_streamFormat = newDescription;
+        if (m_audioSourceProvider)
+            m_audioSourceProvider-&gt;prepare(&amp;m_streamFormat);
+    }
</ins><span class="cx"> 
</span><span class="cx">     WebAudioBufferList audioBufferList { CAAudioStreamDescription(m_streamFormat), WTF::safeCast&lt;uint32_t&gt;(numberOfFrames) };
</span><span class="cx">     audioBufferList.buffer(0)-&gt;mDataByteSize = numberOfChannels * numberOfFrames * bitsPerSample / 8;
</span><span class="lines">@@ -138,8 +143,13 @@
</span><span class="cx"> 
</span><span class="cx"> AudioSourceProvider* RealtimeIncomingAudioSource::audioSourceProvider()
</span><span class="cx"> {
</span><del>-    // FIXME: Create the audioSourceProvider
-    return nullptr;
</del><ins>+    if (!m_audioSourceProvider) {
+        m_audioSourceProvider = WebAudioSourceProviderAVFObjC::create(*this);
+        if (m_numberOfFrames)
+            m_audioSourceProvider-&gt;prepare(&amp;m_streamFormat);
+    }
+
+    return m_audioSourceProvider.get();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacRealtimeIncomingAudioSourceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/RealtimeIncomingAudioSource.h (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/RealtimeIncomingAudioSource.h        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/platform/mediastream/mac/RealtimeIncomingAudioSource.h        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -77,8 +77,8 @@
</span><span class="cx">     rtc::scoped_refptr&lt;webrtc::AudioTrackInterface&gt; m_audioTrack;
</span><span class="cx"> 
</span><span class="cx">     RefPtr&lt;WebAudioSourceProviderAVFObjC&gt; m_audioSourceProvider;
</span><del>-    AudioStreamBasicDescription m_streamFormat;
-    uint64_t m_numberOfFrames;
</del><ins>+    AudioStreamBasicDescription m_streamFormat { };
+    uint64_t m_numberOfFrames { 0 };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacRealtimeOutgoingAudioSourcecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingAudioSource.cpp (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingAudioSource.cpp        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingAudioSource.cpp        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -72,7 +72,8 @@
</span><span class="cx">         auto status  = m_sampleConverter-&gt;setInputFormat(m_inputStreamDescription);
</span><span class="cx">         ASSERT_UNUSED(status, !status);
</span><span class="cx"> 
</span><del>-        status = m_sampleConverter-&gt;setOutputFormat(libwebrtcAudioFormat(streamDescription.sampleRate(), streamDescription.numberOfChannels()));
</del><ins>+        m_outputStreamDescription = libwebrtcAudioFormat(LibWebRTCAudioFormat::sampleRate, streamDescription.numberOfChannels());
+        status = m_sampleConverter-&gt;setOutputFormat(m_outputStreamDescription.streamDescription());
</ins><span class="cx">         ASSERT(!status);
</span><span class="cx">     }
</span><span class="cx">     m_sampleConverter-&gt;pushSamples(time, audioData, sampleCount);
</span><span class="lines">@@ -85,13 +86,13 @@
</span><span class="cx"> void RealtimeOutgoingAudioSource::pullAudioData()
</span><span class="cx"> {
</span><span class="cx">     // libwebrtc expects 10 ms chunks.
</span><del>-    size_t chunkSampleCount = m_inputStreamDescription.sampleRate() / 100;
-    size_t bufferSize = chunkSampleCount * LibWebRTCAudioFormat::sampleByteSize * m_inputStreamDescription.numberOfChannels();
</del><ins>+    size_t chunkSampleCount = m_outputStreamDescription.sampleRate() / 100;
+    size_t bufferSize = chunkSampleCount * LibWebRTCAudioFormat::sampleByteSize * m_outputStreamDescription.numberOfChannels();
</ins><span class="cx">     m_audioBuffer.reserveCapacity(bufferSize);
</span><span class="cx"> 
</span><span class="cx">     AudioBufferList bufferList;
</span><span class="cx">     bufferList.mNumberBuffers = 1;
</span><del>-    bufferList.mBuffers[0].mNumberChannels = m_inputStreamDescription.numberOfChannels();
</del><ins>+    bufferList.mBuffers[0].mNumberChannels = m_outputStreamDescription.numberOfChannels();
</ins><span class="cx">     bufferList.mBuffers[0].mDataByteSize = bufferSize;
</span><span class="cx">     bufferList.mBuffers[0].mData = m_audioBuffer.data();
</span><span class="cx"> 
</span><span class="lines">@@ -98,7 +99,7 @@
</span><span class="cx">     m_sampleConverter-&gt;pullAvalaibleSamplesAsChunks(bufferList, chunkSampleCount, m_startFrame, [this, chunkSampleCount] {
</span><span class="cx">         m_startFrame += chunkSampleCount;
</span><span class="cx">         for (auto sink : m_sinks)
</span><del>-            sink-&gt;OnData(m_audioBuffer.data(), LibWebRTCAudioFormat::sampleSize, m_inputStreamDescription.sampleRate(), m_inputStreamDescription.numberOfChannels(), chunkSampleCount);
</del><ins>+            sink-&gt;OnData(m_audioBuffer.data(), LibWebRTCAudioFormat::sampleSize, m_outputStreamDescription.sampleRate(), m_outputStreamDescription.numberOfChannels(), chunkSampleCount);
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacRealtimeOutgoingAudioSourceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingAudioSource.h (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingAudioSource.h        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/platform/mediastream/mac/RealtimeOutgoingAudioSource.h        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -74,6 +74,7 @@
</span><span class="cx">     rtc::scoped_refptr&lt;webrtc::AudioTrackInterface&gt; m_track;
</span><span class="cx">     Ref&lt;AudioSampleDataSource&gt; m_sampleConverter;
</span><span class="cx">     CAAudioStreamDescription m_inputStreamDescription;
</span><ins>+    CAAudioStreamDescription m_outputStreamDescription;
</ins><span class="cx"> 
</span><span class="cx">     Vector&lt;uint16_t&gt; m_audioBuffer;
</span><span class="cx">     uint64_t m_startFrame { 0 };
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacWebAudioSourceProviderAVFObjCh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/WebAudioSourceProviderAVFObjC.h (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/WebAudioSourceProviderAVFObjC.h        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/platform/mediastream/mac/WebAudioSourceProviderAVFObjC.h        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -41,7 +41,8 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-class CARingBuffer;
</del><ins>+class AudioSampleDataSource;
+class CAAudioStreamDescription;
</ins><span class="cx"> 
</span><span class="cx"> class WebAudioSourceProviderAVFObjC : public RefCounted&lt;WebAudioSourceProviderAVFObjC&gt;, public AudioSourceProvider, RealtimeMediaSource::Observer {
</span><span class="cx"> public:
</span><span class="lines">@@ -62,11 +63,9 @@
</span><span class="cx">     void audioSamplesAvailable(const MediaTime&amp;, const PlatformAudioData&amp;, const AudioStreamDescription&amp;, size_t) final;
</span><span class="cx"> 
</span><span class="cx">     size_t m_listBufferSize { 0 };
</span><del>-    std::unique_ptr&lt;AudioBufferList&gt; m_list;
-    AudioConverterRef m_converter;
-    std::unique_ptr&lt;AudioStreamBasicDescription&gt; m_inputDescription;
-    std::unique_ptr&lt;AudioStreamBasicDescription&gt; m_outputDescription;
-    std::unique_ptr&lt;CARingBuffer&gt; m_ringBuffer;
</del><ins>+    std::unique_ptr&lt;CAAudioStreamDescription&gt; m_inputDescription;
+    std::unique_ptr&lt;CAAudioStreamDescription&gt; m_outputDescription;
+    RefPtr&lt;AudioSampleDataSource&gt; m_dataSource;
</ins><span class="cx"> 
</span><span class="cx">     uint64_t m_writeCount { 0 };
</span><span class="cx">     uint64_t m_readCount { 0 };
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacWebAudioSourceProviderAVFObjCmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/WebAudioSourceProviderAVFObjC.mm (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/WebAudioSourceProviderAVFObjC.mm        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/platform/mediastream/mac/WebAudioSourceProviderAVFObjC.mm        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -30,12 +30,11 @@
</span><span class="cx"> 
</span><span class="cx"> #import &quot;AudioBus.h&quot;
</span><span class="cx"> #import &quot;AudioChannel.h&quot;
</span><ins>+#import &quot;AudioSampleDataSource.h&quot;
</ins><span class="cx"> #import &quot;AudioSourceProviderClient.h&quot;
</span><del>-#import &quot;CARingBuffer.h&quot;
</del><span class="cx"> #import &quot;Logging.h&quot;
</span><span class="cx"> #import &quot;MediaTimeAVFoundation.h&quot;
</span><span class="cx"> #import &quot;WebAudioBufferList.h&quot;
</span><del>-#import &lt;AudioToolbox/AudioToolbox.h&gt;
</del><span class="cx"> #import &lt;objc/runtime.h&gt;
</span><span class="cx"> #import &lt;wtf/MainThread.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -45,11 +44,6 @@
</span><span class="cx"> 
</span><span class="cx"> #import &quot;CoreMediaSoftLink.h&quot;
</span><span class="cx"> 
</span><del>-SOFT_LINK_FRAMEWORK(AudioToolbox)
-
-SOFT_LINK(AudioToolbox, AudioConverterConvertComplexBuffer, OSStatus, (AudioConverterRef inAudioConverter, UInt32 inNumberPCMFrames, const AudioBufferList* inInputData, AudioBufferList* outOutputData), (inAudioConverter, inNumberPCMFrames, inInputData, outOutputData))
-SOFT_LINK(AudioToolbox, AudioConverterNew, OSStatus, (const AudioStreamBasicDescription* inSourceFormat, const AudioStreamBasicDescription* inDestinationFormat, AudioConverterRef* outAudioConverter), (inSourceFormat, inDestinationFormat, outAudioConverter))
-
</del><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> static const double kRingBufferDuration = 1;
</span><span class="lines">@@ -68,11 +62,6 @@
</span><span class="cx"> {
</span><span class="cx">     std::lock_guard&lt;Lock&gt; lock(m_mutex);
</span><span class="cx"> 
</span><del>-    if (m_converter) {
-        // FIXME: make and use a smart pointer for AudioConverter
-        AudioConverterDispose(m_converter);
-        m_converter = nullptr;
-    }
</del><span class="cx">     if (m_connected &amp;&amp; m_captureSource)
</span><span class="cx">         m_captureSource-&gt;removeObserver(*this);
</span><span class="cx"> }
</span><span class="lines">@@ -80,45 +69,27 @@
</span><span class="cx"> void WebAudioSourceProviderAVFObjC::provideInput(AudioBus* bus, size_t framesToProcess)
</span><span class="cx"> {
</span><span class="cx">     std::unique_lock&lt;Lock&gt; lock(m_mutex, std::try_to_lock);
</span><del>-    if (!lock.owns_lock() || !m_ringBuffer) {
</del><ins>+    if (!lock.owns_lock() || !m_dataSource) {
</ins><span class="cx">         bus-&gt;zero();
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    uint64_t startFrame = 0;
-    uint64_t endFrame = 0;
-    m_ringBuffer-&gt;getCurrentFrameBounds(startFrame, endFrame);
-
</del><span class="cx">     if (m_writeCount &lt;= m_readCount) {
</span><span class="cx">         bus-&gt;zero();
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    uint64_t framesAvailable = endFrame - m_readCount;
-    if (framesAvailable &lt; framesToProcess) {
-        framesToProcess = static_cast&lt;size_t&gt;(framesAvailable);
-        bus-&gt;zero();
-    }
-
-    ASSERT(bus-&gt;numberOfChannels() == m_ringBuffer-&gt;channelCount());
-    if (bus-&gt;numberOfChannels() != m_ringBuffer-&gt;channelCount()) {
-        bus-&gt;zero();
-        return;
-    }
-
-    for (unsigned i = 0; i &lt; m_list-&gt;mNumberBuffers; ++i) {
</del><ins>+    WebAudioBufferList list { *m_outputDescription };
+    for (unsigned i = 0; i &lt; list.bufferCount(); ++i) {
</ins><span class="cx">         AudioChannel&amp; channel = *bus-&gt;channel(i);
</span><del>-        auto&amp; buffer = m_list-&gt;mBuffers[i];
-        buffer.mNumberChannels = 1;
-        buffer.mData = channel.mutableData();
-        buffer.mDataByteSize = channel.length() * sizeof(float);
</del><ins>+        auto* buffer = list.buffer(i);
+        buffer-&gt;mNumberChannels = 1;
+        buffer-&gt;mData = channel.mutableData();
+        buffer-&gt;mDataByteSize = channel.length() * sizeof(float);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    m_ringBuffer-&gt;fetch(m_list.get(), framesToProcess, m_readCount);
</del><ins>+    m_dataSource-&gt;pullSamples(*list.list(), framesToProcess, m_readCount, 0, AudioSampleDataSource::Copy);
</ins><span class="cx">     m_readCount += framesToProcess;
</span><del>-
-    if (m_converter)
-        AudioConverterConvertComplexBuffer(m_converter, framesToProcess, m_list.get(), m_list.get());
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebAudioSourceProviderAVFObjC::setClient(AudioSourceProviderClient* client)
</span><span class="lines">@@ -147,59 +118,25 @@
</span><span class="cx"> 
</span><span class="cx">     LOG(Media, &quot;WebAudioSourceProviderAVFObjC::prepare(%p)&quot;, this);
</span><span class="cx"> 
</span><del>-    m_inputDescription = std::make_unique&lt;AudioStreamBasicDescription&gt;(*format);
</del><ins>+    m_inputDescription = std::make_unique&lt;CAAudioStreamDescription&gt;(*format);
</ins><span class="cx">     int numberOfChannels = format-&gt;mChannelsPerFrame;
</span><span class="cx">     double sampleRate = format-&gt;mSampleRate;
</span><span class="cx">     ASSERT(sampleRate &gt;= 0);
</span><span class="cx"> 
</span><del>-    m_outputDescription = std::make_unique&lt;AudioStreamBasicDescription&gt;();
-    m_outputDescription-&gt;mSampleRate = sampleRate;
-    m_outputDescription-&gt;mFormatID = kAudioFormatLinearPCM;
-    m_outputDescription-&gt;mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
-    m_outputDescription-&gt;mBitsPerChannel = 8 * sizeof(Float32);
-    m_outputDescription-&gt;mChannelsPerFrame = numberOfChannels;
-    m_outputDescription-&gt;mFramesPerPacket = 1;
-    m_outputDescription-&gt;mBytesPerPacket = sizeof(Float32);
-    m_outputDescription-&gt;mBytesPerFrame = sizeof(Float32);
-    m_outputDescription-&gt;mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
</del><ins>+    const int bytesPerFloat = sizeof(Float32);
+    const int bitsPerByte = 8;
+    const bool isFloat = true;
+    const bool isBigEndian = false;
+    const bool isNonInterleaved = true;
+    AudioStreamBasicDescription outputDescription { };
+    FillOutASBDForLPCM(outputDescription, sampleRate, numberOfChannels, bitsPerByte * bytesPerFloat, bitsPerByte * bytesPerFloat, isFloat, isBigEndian, isNonInterleaved);
+    m_outputDescription = std::make_unique&lt;CAAudioStreamDescription&gt;(outputDescription);
</ins><span class="cx"> 
</span><del>-    if (m_converter) {
-        // FIXME: make and use a smart pointer for AudioConverter
-        AudioConverterDispose(m_converter);
-        m_converter = nullptr;
-    }
</del><ins>+    if (!m_dataSource)
+        m_dataSource = AudioSampleDataSource::create(kRingBufferDuration * sampleRate);
+    m_dataSource-&gt;setInputFormat(*m_inputDescription);
+    m_dataSource-&gt;setOutputFormat(*m_outputDescription);
</ins><span class="cx"> 
</span><del>-    if (*m_inputDescription != *m_outputDescription) {
-        AudioConverterRef outConverter = nullptr;
-        OSStatus err = AudioConverterNew(m_inputDescription.get(), m_outputDescription.get(), &amp;outConverter);
-        if (err) {
-            LOG(Media, &quot;WebAudioSourceProviderAVFObjC::prepare(%p) - AudioConverterNew returned error %i&quot;, this, err);
-            return;
-        }
-        m_converter = outConverter;
-    }
-
-    // Make the ringbuffer large enough to store 1 second.
-    uint64_t capacity = kRingBufferDuration * sampleRate;
-    ASSERT(capacity &lt;= SIZE_MAX);
-    if (capacity &gt; SIZE_MAX)
-        return;
-
-    // AudioBufferList is a variable-length struct, so create on the heap with a generic new() operator
-    // with a custom size, and initialize the struct manually.
-    uint64_t bufferListSize = offsetof(AudioBufferList, mBuffers) + (sizeof(AudioBuffer) * std::max(1, numberOfChannels));
-    ASSERT(bufferListSize &lt;= SIZE_MAX);
-    if (bufferListSize &gt; SIZE_MAX)
-        return;
-
-    m_ringBuffer = std::make_unique&lt;CARingBuffer&gt;();
-    m_ringBuffer-&gt;allocate(CAAudioStreamDescription(*format), static_cast&lt;size_t&gt;(capacity));
-
-    m_listBufferSize = static_cast&lt;size_t&gt;(bufferListSize);
-    m_list = std::unique_ptr&lt;AudioBufferList&gt;(static_cast&lt;AudioBufferList*&gt;(::operator new (m_listBufferSize)));
-    memset(m_list.get(), 0, m_listBufferSize);
-    m_list-&gt;mNumberBuffers = numberOfChannels;
-
</del><span class="cx">     RefPtr&lt;WebAudioSourceProviderAVFObjC&gt; protectedThis = this;
</span><span class="cx">     callOnMainThread([protectedThis = WTFMove(protectedThis), numberOfChannels, sampleRate] {
</span><span class="cx">         if (protectedThis-&gt;m_client)
</span><span class="lines">@@ -213,29 +150,21 @@
</span><span class="cx"> 
</span><span class="cx">     m_inputDescription = nullptr;
</span><span class="cx">     m_outputDescription = nullptr;
</span><del>-    m_ringBuffer = nullptr;
-    m_list = nullptr;
</del><ins>+    m_dataSource = nullptr;
</ins><span class="cx">     m_listBufferSize = 0;
</span><span class="cx">     if (m_captureSource) {
</span><span class="cx">         m_captureSource-&gt;removeObserver(*this);
</span><span class="cx">         m_captureSource = nullptr;
</span><span class="cx">     }
</span><del>-
-    if (m_converter) {
-        // FIXME: make and use a smart pointer for AudioConverter
-        AudioConverterDispose(m_converter);
-        m_converter = nullptr;
-    }
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebAudioSourceProviderAVFObjC::audioSamplesAvailable(const MediaTime&amp;, const PlatformAudioData&amp; data, const AudioStreamDescription&amp;, size_t frameCount)
</span><span class="cx"> {
</span><del>-    if (!m_ringBuffer)
</del><ins>+    if (!m_dataSource)
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    auto&amp; bufferList = downcast&lt;WebAudioBufferList&gt;(data);
</del><ins>+    m_dataSource-&gt;pushSamples(MediaTime(m_writeCount, m_outputDescription-&gt;sampleRate()), data, frameCount);
</ins><span class="cx"> 
</span><del>-    m_ringBuffer-&gt;store(bufferList.list(), frameCount, m_writeCount);
</del><span class="cx">     m_writeCount += frameCount;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoretestingMockLibWebRTCPeerConnectionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/MockLibWebRTCPeerConnection.h (213079 => 213080)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/MockLibWebRTCPeerConnection.h        2017-02-27 17:51:29 UTC (rev 213079)
+++ trunk/Source/WebCore/testing/MockLibWebRTCPeerConnection.h        2017-02-27 18:22:49 UTC (rev 213080)
</span><span class="lines">@@ -124,8 +124,14 @@
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     webrtc::AudioSourceInterface* GetSource() const final { return m_source; }
</span><del>-    void AddSink(webrtc::AudioTrackSinkInterface*) final { }
-    void RemoveSink(webrtc::AudioTrackSinkInterface*) final { }
</del><ins>+    void AddSink(webrtc::AudioTrackSinkInterface* sink) final {
+        if (m_source)
+            m_source-&gt;AddSink(sink);
+    }
+    void RemoveSink(webrtc::AudioTrackSinkInterface* sink) final {
+        if (m_source)
+            m_source-&gt;RemoveSink(sink);
+    }
</ins><span class="cx">     void RegisterObserver(webrtc::ObserverInterface*) final { }
</span><span class="cx">     void UnregisterObserver(webrtc::ObserverInterface*) final { }
</span><span class="cx"> 
</span><span class="lines">@@ -135,7 +141,7 @@
</span><span class="cx">     TrackState state() const final { return kLive; }
</span><span class="cx">     bool set_enabled(bool enabled) final { m_enabled = enabled; return true; }
</span><span class="cx"> 
</span><del>-    bool m_enabled;
</del><ins>+    bool m_enabled { true };
</ins><span class="cx">     std::string m_id;
</span><span class="cx">     webrtc::AudioSourceInterface* m_source { nullptr };
</span><span class="cx"> };
</span></span></pre>
</div>
</div>

</body>
</html>