WebAudio: limit output level to 0db
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 16 Oct 2012 15:51:25 +0000 (15:51 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 16 Oct 2012 15:51:25 +0000 (15:51 +0000)
https://bugs.webkit.org/show_bug.cgi?id=95792
<rdar://problem/11966135>

Reviewed by Chris Rogers.

.:

Add a manual test to determine that output volume has been limited to 0db.

* ManualTests/webaudio/limit-level-0db.html: Added.

Source/WebCore:

Clamp the output buffer data to the range of [-1,1], which limits
output volume to 0db. This ensures that malicious or poorly-written
pages will not be able to blow through the system volume limit by
creating >0db buffers and effects.

No new tests; added ManualTests/webaudio/limit-level-0db.html.

Clamp the output vector to values of [-1,1]:
* platform/audio/mac/AudioDestinationMac.cpp:
(WebCore::AudioDestinationMac::render):

Add a VectorMath wrapper for vDSP_clip to provide accelerated vector threshold operations:
* platform/audio/VectorMath.h:
* platform/audio/VectorMath.cpp:
(VectorMath):
(WebCore::VectorMath::vclip):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@131459 268f45cc-cd09-0410-ab3c-d52691b4dbfc

ChangeLog
ManualTests/webaudio/limit-level-0db.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/platform/audio/VectorMath.cpp
Source/WebCore/platform/audio/VectorMath.h
Source/WebCore/platform/audio/mac/AudioDestinationMac.cpp

index 59c83a9..56c9457 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2012-10-15  Jer Noble  <jer.noble@apple.com>
+
+        WebAudio: limit output level to 0db
+        https://bugs.webkit.org/show_bug.cgi?id=95792
+        <rdar://problem/11966135>
+
+        Reviewed by Chris Rogers.
+
+        Add a manual test to determine that output volume has been limited to 0db.
+
+        * ManualTests/webaudio/limit-level-0db.html: Added.
+
 2012-10-16  Simon Hausmann  <simon.hausmann@digia.com>
 
         [Qt] Fix support for silent builds
diff --git a/ManualTests/webaudio/limit-level-0db.html b/ManualTests/webaudio/limit-level-0db.html
new file mode 100644 (file)
index 0000000..426103b
--- /dev/null
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Web Audio Sample</title>
+    <script>
+        var context = new webkitAudioContext();
+        var gainNode = context.createGainNode();
+        gainNode.connect(context.destination);
+        gainNode.gain.value = 2;
+
+        var frequency = 1000;
+        var duration = 1000;
+    
+        function playNormal() {
+            var oscillator = context.createOscillator();
+            oscillator.frequency.value = frequency;
+            oscillator.type = 0;
+            oscillator.connect(context.destination);
+            oscillator.noteOn(0);
+            setTimeout(function(){ oscillator.disconnect(); }, duration);
+        }
+        
+        function playLoud() {
+            var oscillator = context.createOscillator();
+            oscillator.frequency.value = frequency;
+            oscillator.type = 0;
+            oscillator.connect(gainNode);
+            oscillator.noteOn(0);
+            setTimeout(function(){ oscillator.disconnect(); }, duration);
+        }
+    </script>
+</head>
+<body>
+    <p>
+        This tests that output audio is clamped to 0db maximum.  Press each button below in turn.  The apparent volume for both should be equal, even though the second button plays with 2x gain of the first. The resulting waveforms are not equal, however, as the second button audio is clipped to a square wave shape.
+    </p>
+    <button onclick="playNormal()">normal volume</button><button onclick="playLoud()">double volume</button>
+</body>
+</html>
index 6c2602b..9800922 100644 (file)
@@ -1,3 +1,28 @@
+2012-10-15  Jer Noble  <jer.noble@apple.com>
+
+        WebAudio: limit output level to 0db
+        https://bugs.webkit.org/show_bug.cgi?id=95792
+        <rdar://problem/11966135>
+
+        Reviewed by Chris Rogers.
+
+        Clamp the output buffer data to the range of [-1,1], which limits
+        output volume to 0db. This ensures that malicious or poorly-written
+        pages will not be able to blow through the system volume limit by
+        creating >0db buffers and effects.
+
+        No new tests; added ManualTests/webaudio/limit-level-0db.html.
+
+        Clamp the output vector to values of [-1,1]:
+        * platform/audio/mac/AudioDestinationMac.cpp:
+        (WebCore::AudioDestinationMac::render):
+
+        Add a VectorMath wrapper for vDSP_clip to provide accelerated vector threshold operations:
+        * platform/audio/VectorMath.h:
+        * platform/audio/VectorMath.cpp:
+        (VectorMath):
+        (WebCore::VectorMath::vclip):
+
 2012-10-15  Vsevolod Vlasov  <vsevik@chromium.org>
 
         Web Inspector: Extract domain specific editing handling logic from UISourceCode (step 2).
index 3457995..bb20cee 100644 (file)
@@ -111,6 +111,11 @@ void vsvesq(const float* sourceP, int sourceStride, float* sumP, size_t framesTo
 {
     vDSP_svesq(const_cast<float*>(sourceP), sourceStride, sumP, framesToProcess);
 }
+
+void vclip(const float* sourceP, int sourceStride, const float* lowThresholdP, const float* highThresholdP, float* destP, int destStride, size_t framesToProcess)
+{
+    vDSP_vclip(const_cast<float*>(sourceP), sourceStride, const_cast<float*>(lowThresholdP), const_cast<float*>(highThresholdP), destP, destStride, framesToProcess);
+}
 #else
 
 void vsma(const float* sourceP, int sourceStride, const float* scale, float* destP, int destStride, size_t framesToProcess)
@@ -642,6 +647,22 @@ void vmaxmgv(const float* sourceP, int sourceStride, float* maxP, size_t framesT
     ASSERT(maxP);
     *maxP = max;
 }
+
+void vclip(const float* sourceP, int sourceStride, const float* lowThresholdP, const float* highThresholdP, float* destP, int destStride, size_t framesToProcess)
+{
+    int n = framesToProcess;
+    float lowThreshold = *lowThresholdP;
+    float highThreshold = *highThresholdP;
+
+    // FIXME: Optimize for SSE2.
+    // FIXME: Optimize for NEON.
+    while (n--) {
+        *destP = std::max(std::min(*sourceP, highThreshold), lowThreshold);
+        sourceP += sourceStride;
+        destP += destStride;
+    }
+}
+
 #endif // OS(DARWIN)
 
 } // namespace VectorMath
index 7022519..863bc4b 100644 (file)
@@ -49,6 +49,9 @@ void vmul(const float* source1P, int sourceStride1, const float* source2P, int s
 // Multiplies two complex vectors.
 void zvmul(const float* real1P, const float* imag1P, const float* real2P, const float* imag2P, float* realDestP, float* imagDestP, size_t framesToProcess);
 
+// Copies elements while clipping values to the threshold inputs.
+void vclip(const float* sourceP, int sourceStride, const float* lowThresholdP, const float* highThresholdP, float* destP, int destStride, size_t framesToProcess);
+
 } // namespace VectorMath
 
 } // namespace WebCore
index 95d2eb3..88bccf9 100644 (file)
 
 #include "AudioIOCallback.h"
 #include "FloatConversion.h"
+#include "VectorMath.h"
 #include <CoreAudio/AudioHardware.h>
 
 namespace WebCore {
 
 const int kBufferSize = 128;
+const float kLowThreshold = -1;
+const float kHighThreshold = 1;
 
 // Factory method: Mac-implementation
 PassOwnPtr<AudioDestination> AudioDestination::create(AudioIOCallback& callback, float sampleRate)
@@ -158,6 +161,12 @@ OSStatus AudioDestinationMac::render(UInt32 numberOfFrames, AudioBufferList* ioD
     // FIXME: Add support for local/live audio input.
     m_callback.render(0, &m_renderBus, numberOfFrames);
 
+    // Clamp values at 0db (i.e., [-1.0, 1.0])
+    for (unsigned i = 0; i < m_renderBus.numberOfChannels(); ++i) {
+        AudioChannel* channel = m_renderBus.channel(i);
+        VectorMath::vclip(channel->data(), 1, &kLowThreshold, &kHighThreshold, channel->mutableData(), 1, numberOfFrames);
+    }
+
     return noErr;
 }