<!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>[212725] trunk/Source/WebCore</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/212725">212725</a></dd>
<dt>Author</dt> <dd>jer.noble@apple.com</dd>
<dt>Date</dt> <dd>2017-02-21 10:28:47 -0800 (Tue, 21 Feb 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Give the Mock audio input a &quot;hum&quot; to make drop-outs more detectable
https://bugs.webkit.org/show_bug.cgi?id=168641

Reviewed by Eric Carlson.

Add two helper functions to generate waveforms: addHum() and writeHum(). Use these methods
to create a bip-bop audio buffer which can be used to &quot;blit&quot; a portion the waveform into the
destination buffer during rendering. The background hum must be seamless across multiple
pull operations, so add the hum sound during rendering.

To ensure the waveform buffer is created, initialize the sampleRate to zero, then call
applySampleRate() with the desired default rate, 44.1kHz.

* platform/mediastream/mac/MockRealtimeAudioSourceMac.h:
* platform/mediastream/mac/MockRealtimeAudioSourceMac.mm:
(WebCore::writeHum):
(WebCore::addHum):
(WebCore::MockRealtimeAudioSource::create):
(WebCore::MockRealtimeAudioSourceMac::render):
(WebCore::MockRealtimeAudioSourceMac::applySampleRate):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</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>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (212724 => 212725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-02-21 18:24:51 UTC (rev 212724)
+++ trunk/Source/WebCore/ChangeLog        2017-02-21 18:28:47 UTC (rev 212725)
</span><span class="lines">@@ -1,5 +1,28 @@
</span><span class="cx"> 2017-02-21  Jer Noble  &lt;jer.noble@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Give the Mock audio input a &quot;hum&quot; to make drop-outs more detectable
+        https://bugs.webkit.org/show_bug.cgi?id=168641
+
+        Reviewed by Eric Carlson.
+
+        Add two helper functions to generate waveforms: addHum() and writeHum(). Use these methods
+        to create a bip-bop audio buffer which can be used to &quot;blit&quot; a portion the waveform into the
+        destination buffer during rendering. The background hum must be seamless across multiple
+        pull operations, so add the hum sound during rendering.
+
+        To ensure the waveform buffer is created, initialize the sampleRate to zero, then call
+        applySampleRate() with the desired default rate, 44.1kHz.
+
+        * platform/mediastream/mac/MockRealtimeAudioSourceMac.h:
+        * platform/mediastream/mac/MockRealtimeAudioSourceMac.mm:
+        (WebCore::writeHum):
+        (WebCore::addHum):
+        (WebCore::MockRealtimeAudioSource::create):
+        (WebCore::MockRealtimeAudioSourceMac::render):
+        (WebCore::MockRealtimeAudioSourceMac::applySampleRate):
+
+2017-02-21  Jer Noble  &lt;jer.noble@apple.com&gt;
+
</ins><span class="cx">         Make TrackPrivateBase ThreadSafeRefCounted, so that it can be retained in non-main threads
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=168642
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacMockRealtimeAudioSourceMach"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.h (212724 => 212725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.h        2017-02-21 18:24:51 UTC (rev 212724)
+++ trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.h        2017-02-21 18:28:47 UTC (rev 212725)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> #include &quot;FontCascade.h&quot;
</span><span class="cx"> #include &quot;MockRealtimeAudioSource.h&quot;
</span><span class="cx"> #include &lt;CoreAudio/CoreAudioTypes.h&gt;
</span><ins>+#include &lt;wtf/Vector.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> OBJC_CLASS AVAudioPCMBuffer;
</span><span class="cx"> typedef struct OpaqueCMClock* CMClockRef;
</span><span class="lines">@@ -64,12 +65,15 @@
</span><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 { 44100 };
-    uint64_t m_bytesEmitted { 0 };
</del><ins>+    uint32_t m_sampleRate { 0 };
+    uint64_t m_samplesEmitted { 0 };
+    uint64_t m_samplesRendered { 0 };
</ins><span class="cx"> 
</span><span class="cx">     RetainPtr&lt;CMFormatDescriptionRef&gt; m_formatDescription;
</span><span class="cx">     AudioStreamBasicDescription m_streamFormat;
</span><span class="cx">     RefPtr&lt;WebAudioSourceProviderAVFObjC&gt; m_audioSourceProvider;
</span><ins>+
+    Vector&lt;float&gt; m_bipBopBuffer;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmediastreammacMockRealtimeAudioSourceMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm (212724 => 212725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm        2017-02-21 18:24:51 UTC (rev 212724)
+++ trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm        2017-02-21 18:28:47 UTC (rev 212725)
</span><span class="lines">@@ -57,6 +57,33 @@
</span><span class="cx">     return (size + 15) &amp; ~15;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static const double Tau = 2 * M_PI;
+static const double BipBopDuration = 0.07;
+static const double BipBopVolume = 0.5;
+static const double BipFrequency = 1500;
+static const double BopFrequency = 500;
+static const double HumFrequency = 150;
+static const double HumVolume = 0.1;
+
+template &lt;typename AudioSampleType&gt;
+static void writeHum(float amplitude, float frequency, float sampleRate, AudioSampleType *p, uint64_t count)
+{
+    float humPeriod = sampleRate / frequency;
+    for (uint64_t i = 0; i &lt; count; ++i)
+        *p++ = amplitude * sin(i * Tau / humPeriod);
+}
+
+template &lt;typename AudioSampleType&gt;
+static void addHum(float amplitude, float frequency, float sampleRate, uint64_t start, AudioSampleType *p, uint64_t count)
+{
+    float humPeriod = sampleRate / frequency;
+    for (uint64_t i = start, end = start + count; i &lt; end; ++i) {
+        AudioSampleType a = amplitude * sin(i * Tau / humPeriod);
+        a += *p;
+        *p++ = a;
+    }
+}
+
</ins><span class="cx"> RefPtr&lt;MockRealtimeAudioSource&gt; MockRealtimeAudioSource::create(const String&amp; name, const MediaConstraints* constraints)
</span><span class="cx"> {
</span><span class="cx">     auto source = adoptRef(new MockRealtimeAudioSourceMac(name));
</span><span class="lines">@@ -63,6 +90,8 @@
</span><span class="cx">     if (constraints &amp;&amp; source-&gt;applyConstraints(*constraints))
</span><span class="cx">         source = nullptr;
</span><span class="cx"> 
</span><ins>+    source-&gt;applySampleRate(44100);
+
</ins><span class="cx">     return source;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -90,8 +119,8 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_formatDescription);
</span><span class="cx"> 
</span><del>-    CMTime startTime = CMTimeMake(m_bytesEmitted, m_sampleRate);
-    m_bytesEmitted += frameCount;
</del><ins>+    CMTime startTime = CMTimeMake(m_samplesEmitted, m_sampleRate);
+    m_samplesEmitted += frameCount;
</ins><span class="cx"> 
</span><span class="cx">     audioSamplesAvailable(toMediaTime(startTime), *m_audioBufferList, CAAudioStreamDescription(m_streamFormat), frameCount);
</span><span class="cx"> }
</span><span class="lines">@@ -121,54 +150,24 @@
</span><span class="cx">     if (m_muted || !m_enabled)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    static double theta;
-    static const double frequencies[] = { 1500., 500. };
-    static const double tau = 2 * M_PI;
-
</del><span class="cx">     if (!m_audioBufferList)
</span><span class="cx">         reconfigure();
</span><span class="cx"> 
</span><span class="cx">     uint32_t totalFrameCount = alignTo16Bytes(delta * m_sampleRate);
</span><span class="cx">     uint32_t frameCount = std::min(totalFrameCount, m_maximiumFrameCount);
</span><del>-    double elapsed = elapsedTime();
</del><span class="cx"> 
</span><span class="cx">     while (frameCount) {
</span><ins>+        uint32_t bipBopStart = m_samplesRendered % m_bipBopBuffer.size();
+        uint32_t bipBopRemain = m_bipBopBuffer.size() - bipBopStart;
+        uint32_t bipBopCount = std::min(frameCount, bipBopRemain);
</ins><span class="cx">         for (auto&amp; audioBuffer : m_audioBufferList-&gt;buffers()) {
</span><span class="cx">             audioBuffer.mDataByteSize = frameCount * m_streamFormat.mBytesPerFrame;
</span><del>-            float *buffer = static_cast&lt;float *&gt;(audioBuffer.mData);
-            for (uint32_t frame = 0; frame &lt; frameCount; ++frame) {
-                int phase = fmod(elapsed, 2) * 15;
-                double increment = 0;
-                bool silent = true;
-
-                switch (phase) {
-                case 0:
-                case 14: {
-                    int index = fmod(elapsed, 1) * 2;
-                    increment = tau * frequencies[index] / m_sampleRate;
-                    silent = false;
-                    break;
-                }
-                default:
-                    break;
-                }
-
-                if (silent) {
-                    buffer[frame] = 0;
-                    continue;
-                }
-
-                float tone = sin(theta) * 0.25;
-                buffer[frame] = tone;
-
-                theta += increment;
-                if (theta &gt; tau)
-                    theta -= tau;
-                elapsed += 1 / m_sampleRate;
-            }
</del><ins>+            memcpy(audioBuffer.mData, &amp;m_bipBopBuffer[bipBopStart], sizeof(Float32) * bipBopCount);
+            addHum(HumVolume, HumFrequency, m_sampleRate, m_samplesRendered, static_cast&lt;float*&gt;(audioBuffer.mData), bipBopCount);
</ins><span class="cx">         }
</span><del>-        emitSampleBuffers(frameCount);
-        totalFrameCount -= frameCount;
</del><ins>+        emitSampleBuffers(bipBopCount);
+        m_samplesRendered += bipBopCount;
+        totalFrameCount -= bipBopCount;
</ins><span class="cx">         frameCount = std::min(totalFrameCount, m_maximiumFrameCount);
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -186,6 +185,18 @@
</span><span class="cx">     m_audioBufferList = nullptr;
</span><span class="cx">     m_audioBufferListBufferSize = 0;
</span><span class="cx"> 
</span><ins>+    size_t sampleCount = 2 * m_sampleRate;
+
+    m_bipBopBuffer.grow(sampleCount);
+    m_bipBopBuffer.fill(0);
+
+    size_t bipBopSampleCount = ceil(BipBopDuration * m_sampleRate);
+    size_t bipStart = 0;
+    size_t bopStart = m_sampleRate;
+
+    addHum(BipBopVolume, BipFrequency, m_sampleRate, 0, m_bipBopBuffer.data() + bipStart, bipBopSampleCount);
+    addHum(BipBopVolume, BopFrequency, m_sampleRate, 0, m_bipBopBuffer.data() + bopStart, bipBopSampleCount);
+
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>