Check AudioContext createChannelMerger() for thread safety
authorcrogers@google.com <crogers@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 Sep 2011 19:22:59 +0000 (19:22 +0000)
committercrogers@google.com <crogers@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 Sep 2011 19:22:59 +0000 (19:22 +0000)
https://bugs.webkit.org/show_bug.cgi?id=67247

Reviewed by Kenneth Russell.

Source/WebCore:

Test: webaudio/audiochannelmerger-stereo.html

* webaudio/AudioChannelMerger.cpp:
(WebCore::AudioChannelMerger::process):
(WebCore::AudioChannelMerger::checkNumberOfChannelsForInput):
* webaudio/AudioChannelMerger.h:

LayoutTests:

* webaudio/audiochannelmerger-stereo-expected.txt: Added.
* webaudio/audiochannelmerger-stereo.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/webaudio/audiochannelmerger-stereo-expected.txt [new file with mode: 0644]
LayoutTests/webaudio/audiochannelmerger-stereo.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/webaudio/AudioChannelMerger.cpp
Source/WebCore/webaudio/AudioChannelMerger.h

index ab67bf7..400b0eb 100644 (file)
@@ -1,3 +1,13 @@
+2011-09-08  Chris Rogers  <crogers@google.com>
+
+        Check AudioContext createChannelMerger() for thread safety
+        https://bugs.webkit.org/show_bug.cgi?id=67247
+
+        Reviewed by Kenneth Russell.
+
+        * webaudio/audiochannelmerger-stereo-expected.txt: Added.
+        * webaudio/audiochannelmerger-stereo.html: Added.
+
 2011-09-08  Fady Samuel  <fsamuel@chromium.org>
 
         Fixed Layout Mode should be adjustable from layoutTestController for testing on Chromium platforms
 2011-09-08  Fady Samuel  <fsamuel@chromium.org>
 
         Fixed Layout Mode should be adjustable from layoutTestController for testing on Chromium platforms
diff --git a/LayoutTests/webaudio/audiochannelmerger-stereo-expected.txt b/LayoutTests/webaudio/audiochannelmerger-stereo-expected.txt
new file mode 100644 (file)
index 0000000..4a1b065
--- /dev/null
@@ -0,0 +1,9 @@
+Tests audio channel merging of two mono streams into a single stereo stream.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS Correctly merged from two mono streams to stereo.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webaudio/audiochannelmerger-stereo.html b/LayoutTests/webaudio/audiochannelmerger-stereo.html
new file mode 100644 (file)
index 0000000..a34c86d
--- /dev/null
@@ -0,0 +1,117 @@
+<!DOCTYPE html>
+
+<!--
+Tests that that we can merge two mono streams into a stereo stream.
+-->
+
+<html>
+<head>
+<link rel="stylesheet" href="../fast/js/resources/js-test-style.css"/>
+<script src="../fast/js/resources/js-test-pre.js"></script>
+<script type="text/javascript" src="resources/audio-testing.js"></script>
+<script type="text/javascript" src="resources/buffer-loader.js"></script>
+</head>
+
+<body>
+
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+description("Tests audio channel merging of two mono streams into a single stereo stream.");
+
+var sampleRate = 44100.0;
+var lengthInSampleFrames = 512;
+
+var context = 0;
+var bufferLoader = 0;
+var buffer1;
+var buffer2;
+var bufferSource1;
+var bufferSource2;
+var channelMerger;
+
+function createBufferWithDCOffset(length, sampleRate, offset) {
+    var buffer = context.createBuffer(1, length, sampleRate);
+    var data = buffer.getChannelData(0);
+    for (var i = 0; i < buffer.length; ++i)
+        data[i] = offset;
+    
+    return buffer;
+}
+
+// checkResult() checks that the rendered buffer is stereo and that the left channel is all -1 and right channel all +1.
+function checkResult(event) {
+    var buffer = event.renderedBuffer;
+
+    var success = true;
+
+    if (buffer.numberOfChannels == 2) {
+        var bufferDataL = buffer.getChannelData(0);
+        var bufferDataR = buffer.getChannelData(1);
+    
+        // Go through every sample and make sure it's all -1 for the left-channel, and all +1 for the right-channel.
+        for (var i = 0; i < buffer.length; ++i) {
+            if (bufferDataL[i] != -1 || bufferDataR[i] != 1) {
+                success = false;
+                break;
+            }
+        }
+    } else {
+        success = false;
+    }
+
+    if (success) {
+        testPassed("Correctly merged from two mono streams to stereo.");
+    } else {
+        testFailed("Merging error from two mono streams to stereo.");
+    }
+
+    finishJSTest();
+}
+
+function runTest() {
+    if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+    }
+    
+    window.jsTestIsAsync = true;
+        
+    // Create stereo offline audio context.
+    context = new webkitAudioContext(2, lengthInSampleFrames, sampleRate);
+
+    // Create two mono buffers, one having all -1 values, the other all +1.
+    buffer1 = createBufferWithDCOffset(lengthInSampleFrames, sampleRate, -1);
+    buffer2 = createBufferWithDCOffset(lengthInSampleFrames, sampleRate, 1);
+
+    // Create a buffer source for each of these buffers.
+    bufferSource1 = context.createBufferSource();
+    bufferSource2 = context.createBufferSource();
+    bufferSource1.buffer = buffer1;
+    bufferSource2.buffer = buffer2;
+
+    // Create a channel merger and connect it so that it merges two mono streams into a single stereo stream.
+    
+    channelMerger = context.createChannelMerger();
+    bufferSource1.connect(channelMerger, 0, 0); // connect to input 0 of the channel merger
+    bufferSource2.connect(channelMerger, 0, 1); // connect to input 1 of the channel merger
+    
+    channelMerger.connect(context.destination);
+
+    // Trigger both sources to start at the beginning.
+    bufferSource1.noteOn(0);
+    bufferSource2.noteOn(0);
+    
+    context.oncomplete = checkResult;
+    context.startRendering();
+}
+
+runTest();
+successfullyParsed = true;
+
+</script>
+
+<script src="../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
index 2bdc7b6..39e6039 100644 (file)
@@ -1,3 +1,17 @@
+2011-09-08  Chris Rogers  <crogers@google.com>
+
+        Check AudioContext createChannelMerger() for thread safety
+        https://bugs.webkit.org/show_bug.cgi?id=67247
+
+        Reviewed by Kenneth Russell.
+
+        Test: webaudio/audiochannelmerger-stereo.html
+
+        * webaudio/AudioChannelMerger.cpp:
+        (WebCore::AudioChannelMerger::process):
+        (WebCore::AudioChannelMerger::checkNumberOfChannelsForInput):
+        * webaudio/AudioChannelMerger.h:
+
 2011-09-08  Ned Holbrook  <nholbrook@apple.com>
 
         Refactor hyphen measurement
 2011-09-08  Ned Holbrook  <nholbrook@apple.com>
 
         Refactor hyphen measurement
index c418a61..eb5b80c 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "AudioChannelMerger.h"
 
 
 #include "AudioChannelMerger.h"
 
+#include "AudioContext.h"
 #include "AudioNodeInput.h"
 #include "AudioNodeOutput.h"
 
 #include "AudioNodeInput.h"
 #include "AudioNodeOutput.h"
 
@@ -61,18 +62,7 @@ void AudioChannelMerger::process(size_t framesToProcess)
     ASSERT(output);
     ASSERT_UNUSED(framesToProcess, framesToProcess == output->bus()->length());    
     
     ASSERT(output);
     ASSERT_UNUSED(framesToProcess, framesToProcess == output->bus()->length());    
     
-    // Count how many channels we have all together from all of the inputs.
-    unsigned numberOfOutputChannels = 0;
-    for (unsigned i = 0; i < numberOfInputs(); ++i) {
-        AudioNodeInput* input = this->input(i);
-        if (input->isConnected())
-            numberOfOutputChannels += input->bus()->numberOfChannels();
-    }
-
-    // Set the correct number of channels on the output
-    output->setNumberOfChannels(numberOfOutputChannels);
-    
-    // Now merge the channels back into one output.
+    // Merge all the channels from all the inputs into one output.
     unsigned outputChannelIndex = 0;
     for (unsigned i = 0; i < numberOfInputs(); ++i) {
         AudioNodeInput* input = this->input(i);
     unsigned outputChannelIndex = 0;
     for (unsigned i = 0; i < numberOfInputs(); ++i) {
         AudioNodeInput* input = this->input(i);
@@ -90,13 +80,33 @@ void AudioChannelMerger::process(size_t framesToProcess)
         }
     }
     
         }
     }
     
-    ASSERT(outputChannelIndex == numberOfOutputChannels);
+    ASSERT(outputChannelIndex == output->numberOfChannels());
 }
 
 void AudioChannelMerger::reset()
 {
 }
 
 }
 
 void AudioChannelMerger::reset()
 {
 }
 
+// Any time a connection or disconnection happens on any of our inputs, we potentially need to change the
+// number of channels of our output.
+void AudioChannelMerger::checkNumberOfChannelsForInput(AudioNodeInput* input)
+{
+    ASSERT(context()->isAudioThread() && context()->isGraphOwner());
+
+    // Count how many channels we have all together from all of the inputs.
+    unsigned numberOfOutputChannels = 0;
+    for (unsigned i = 0; i < numberOfInputs(); ++i) {
+        AudioNodeInput* input = this->input(i);
+        if (input->isConnected())
+            numberOfOutputChannels += input->bus()->numberOfChannels();
+    }
+
+    // Set the correct number of channels on the output
+    AudioNodeOutput* output = this->output(0);
+    ASSERT(output);
+    output->setNumberOfChannels(numberOfOutputChannels);
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WEB_AUDIO)
 } // namespace WebCore
 
 #endif // ENABLE(WEB_AUDIO)
index 20a9628..b7b718b 100644 (file)
@@ -47,6 +47,9 @@ public:
     virtual void process(size_t framesToProcess);
     virtual void reset();
 
     virtual void process(size_t framesToProcess);
     virtual void reset();
 
+    // Called in the audio thread (pre-rendering task) when the number of channels for an input may have changed.
+    virtual void checkNumberOfChannelsForInput(AudioNodeInput*);
+
 private:
     AudioChannelMerger(AudioContext*, double sampleRate);
 };
 private:
     AudioChannelMerger(AudioContext*, double sampleRate);
 };