Title: [115787] trunk
Revision
115787
Author
[email protected]
Date
2012-05-01 20:38:23 -0700 (Tue, 01 May 2012)

Log Message

Modify RealtimeAnalyserNode pull mechanism
https://bugs.webkit.org/show_bug.cgi?id=77515

Patch by Raymond Liu <[email protected]> on 2012-05-01
Reviewed by Chris Rogers.

Source/WebCore:

Test: webaudio/automatic-pull-node.html

* GNUmakefile.list.am:
* Modules/webaudio/AudioBasicInspectorNode.cpp: Added.
(WebCore):
(WebCore::AudioBasicInspectorNode::AudioBasicInspectorNode):
(WebCore::AudioBasicInspectorNode::pullInputs):
(WebCore::AudioBasicInspectorNode::connect):
(WebCore::AudioBasicInspectorNode::disconnect):
(WebCore::AudioBasicInspectorNode::checkNumberOfChannelsForInput):
(WebCore::AudioBasicInspectorNode::updatePullStatus):
* Modules/webaudio/AudioBasicInspectorNode.h: Added.
(WebCore):
(AudioBasicInspectorNode):
* Modules/webaudio/AudioContext.cpp:
(WebCore::AudioContext::AudioContext):
(WebCore::AudioContext::~AudioContext):
(WebCore::AudioContext::handlePreRenderTasks):
(WebCore::AudioContext::handlePostRenderTasks):
(WebCore::AudioContext::markForDeletion):
(WebCore):
(WebCore::AudioContext::addAutomaticPullNode):
(WebCore::AudioContext::removeAutomaticPullNode):
(WebCore::AudioContext::updateAutomaticPullNodes):
(WebCore::AudioContext::processAutomaticPullNodes):
* Modules/webaudio/AudioContext.h:
(AudioContext):
* Modules/webaudio/AudioDestinationNode.cpp:
(WebCore::AudioDestinationNode::provideInput):
* Modules/webaudio/AudioNode.h:
(AudioNode):
* Modules/webaudio/AudioNodeOutput.h:
(WebCore::AudioNodeOutput::isConnected):
(AudioNodeOutput):
* Modules/webaudio/RealtimeAnalyserNode.cpp:
(WebCore::RealtimeAnalyserNode::RealtimeAnalyserNode):
* Modules/webaudio/RealtimeAnalyserNode.h:
(RealtimeAnalyserNode):
* WebCore.gypi:
* WebCore.xcodeproj/project.pbxproj:

LayoutTests:

* webaudio/automatic-pull-node-expected.txt: Added.
* webaudio/automatic-pull-node.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (115786 => 115787)


--- trunk/LayoutTests/ChangeLog	2012-05-02 03:35:48 UTC (rev 115786)
+++ trunk/LayoutTests/ChangeLog	2012-05-02 03:38:23 UTC (rev 115787)
@@ -1,3 +1,13 @@
+2012-05-01  Raymond Liu  <[email protected]>
+
+        Modify RealtimeAnalyserNode pull mechanism
+        https://bugs.webkit.org/show_bug.cgi?id=77515
+
+        Reviewed by Chris Rogers.
+
+        * webaudio/automatic-pull-node-expected.txt: Added.
+        * webaudio/automatic-pull-node.html: Added.
+
 2012-05-01  Keishi Hattori  <[email protected]>
 
         datalist: Form control in a <datalist> should be barred from constraint validation

Added: trunk/LayoutTests/webaudio/automatic-pull-node-expected.txt (0 => 115787)


--- trunk/LayoutTests/webaudio/automatic-pull-node-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webaudio/automatic-pull-node-expected.txt	2012-05-02 03:38:23 UTC (rev 115787)
@@ -0,0 +1,11 @@
+This test verifies that the AudioBasicInspectorNode based nodes work correctly.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS RealtimeAnalyserNode got pulled when connected from upstream node but not to downstream node.
+PASS RealtimeAnalyserNode got pulled when connected from upstream node and to destination node.
+PASS RealtimeAnalyserNode didn't get pulled when it should not.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/webaudio/automatic-pull-node.html (0 => 115787)


--- trunk/LayoutTests/webaudio/automatic-pull-node.html	                        (rev 0)
+++ trunk/LayoutTests/webaudio/automatic-pull-node.html	2012-05-02 03:38:23 UTC (rev 115787)
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<script src=""
+<script type="text/_javascript_" src=""
+</head>
+
+<body>
+
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+description("This test verifies that the AudioBasicInspectorNode based nodes work correctly.");
+
+var sampleRate = 44100.0;
+// We carefully arrange the renderLengthInFrames to be a multiple of the AudioNode rendering quantum (AudioNode::ProcessingSizeInFrames)
+// so that AudioSourceNode will not feed tailing zeroes into the context and fail this test.
+var renderLengthInFrames = 256;
+var fftSize = 64;
+
+var audioDataOne = 255; // Audio data 1.0 in Uint8 format will be 255.
+var audioDataZero = 128; // Audio data 0 in Uint8 format will be 128.
+
+var context;
+var constantBuffer;
+var bufferSource;
+var analyser;
+
+function constructCommonGraph() {
+    // Create offline audio context.
+    context = new webkitAudioContext(1, renderLengthInFrames, sampleRate);
+    constantBuffer = createConstantBuffer(context, renderLengthInFrames, 1);
+
+    bufferSource = context.createBufferSource();
+    bufferSource.buffer = constantBuffer;
+
+    analyser = context.createAnalyser();
+    analyser.fftSize = fftSize;
+
+    bufferSource.connect(analyser);
+}
+
+function test1Finished() {
+    var timeDomainData = new Uint8Array(fftSize);
+    analyser.getByteTimeDomainData(timeDomainData);
+
+    if (timeDomainData[0] >= audioDataOne)
+        testPassed("RealtimeAnalyserNode got pulled when connected from upstream node but not to downstream node.");
+    else
+        testFailed("RealtimeAnalyserNode failed to get pulled when connected from upstream node but not to downstream node.");
+
+    test2();
+}
+
+// To verify the realtimeAnalyser can pull data when there is an upstream node connected to it
+// but it's not connected to a downstream node.
+function test1() {
+    constructCommonGraph();
+
+    bufferSource.noteOn(0);
+
+    context._oncomplete_ = test1Finished;
+    context.startRendering();
+}
+
+function test2Finished() {
+    var timeDomainData = new Uint8Array(fftSize);
+    analyser.getByteTimeDomainData(timeDomainData);
+
+    if (timeDomainData[0] >= audioDataOne)
+        testPassed("RealtimeAnalyserNode got pulled when connected from upstream node and to destination node.");
+    else
+        testFailed("RealtimeAnalyserNode failed to be pulled when connected by upstream node and to destination node.");
+
+    test3();
+}
+
+// To verify the realtimeAnalyser can process normally when there is an upstream node connected to it
+// and it's also connected to a downstream node which ultimately connect to audio destination.
+function test2() {
+    constructCommonGraph();
+
+    analyser.connect(context.destination);
+
+    bufferSource.noteOn(0);
+
+    context._oncomplete_ = test2Finished;
+    context.startRendering();
+}
+
+function test3Finished() {
+    var timeDomainData = new Uint8Array(fftSize);
+    analyser.getByteTimeDomainData(timeDomainData);
+
+    // If realtimeAnalyser hasn't pulled any data, the data in buffer will be 0.
+    if (timeDomainData[0] == audioDataZero)
+        testPassed("RealtimeAnalyserNode didn't get pulled when it should not.");
+    else
+        testFailed("RealtimeAnalyserNode been pulled when it should not.");
+
+    finishJSTest();
+}
+
+// To verify the realtimeAnalyser will stop pulling if it is connected to a downstream node
+// which is not ultimatly connected to any audio destination.
+function test3() {
+    constructCommonGraph();
+
+    var gain = context.createGainNode();
+    analyser.connect(gain);
+
+    bufferSource.noteOn(0);
+
+    context._oncomplete_ = test3Finished;
+    context.startRendering();
+}
+
+function runTest() {
+    if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+    }
+
+    window.jsTestIsAsync = true;
+
+    test1();
+}
+
+runTest();
+
+</script>
+
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (115786 => 115787)


--- trunk/Source/WebCore/ChangeLog	2012-05-02 03:35:48 UTC (rev 115786)
+++ trunk/Source/WebCore/ChangeLog	2012-05-02 03:38:23 UTC (rev 115787)
@@ -1,3 +1,51 @@
+2012-05-01  Raymond Liu  <[email protected]>
+
+        Modify RealtimeAnalyserNode pull mechanism
+        https://bugs.webkit.org/show_bug.cgi?id=77515
+
+        Reviewed by Chris Rogers.
+
+        Test: webaudio/automatic-pull-node.html
+
+        * GNUmakefile.list.am:
+        * Modules/webaudio/AudioBasicInspectorNode.cpp: Added.
+        (WebCore):
+        (WebCore::AudioBasicInspectorNode::AudioBasicInspectorNode):
+        (WebCore::AudioBasicInspectorNode::pullInputs):
+        (WebCore::AudioBasicInspectorNode::connect):
+        (WebCore::AudioBasicInspectorNode::disconnect):
+        (WebCore::AudioBasicInspectorNode::checkNumberOfChannelsForInput):
+        (WebCore::AudioBasicInspectorNode::updatePullStatus):
+        * Modules/webaudio/AudioBasicInspectorNode.h: Added.
+        (WebCore):
+        (AudioBasicInspectorNode):
+        * Modules/webaudio/AudioContext.cpp:
+        (WebCore::AudioContext::AudioContext):
+        (WebCore::AudioContext::~AudioContext):
+        (WebCore::AudioContext::handlePreRenderTasks):
+        (WebCore::AudioContext::handlePostRenderTasks):
+        (WebCore::AudioContext::markForDeletion):
+        (WebCore):
+        (WebCore::AudioContext::addAutomaticPullNode):
+        (WebCore::AudioContext::removeAutomaticPullNode):
+        (WebCore::AudioContext::updateAutomaticPullNodes):
+        (WebCore::AudioContext::processAutomaticPullNodes):
+        * Modules/webaudio/AudioContext.h:
+        (AudioContext):
+        * Modules/webaudio/AudioDestinationNode.cpp:
+        (WebCore::AudioDestinationNode::provideInput):
+        * Modules/webaudio/AudioNode.h:
+        (AudioNode):
+        * Modules/webaudio/AudioNodeOutput.h:
+        (WebCore::AudioNodeOutput::isConnected):
+        (AudioNodeOutput):
+        * Modules/webaudio/RealtimeAnalyserNode.cpp:
+        (WebCore::RealtimeAnalyserNode::RealtimeAnalyserNode):
+        * Modules/webaudio/RealtimeAnalyserNode.h:
+        (RealtimeAnalyserNode):
+        * WebCore.gypi:
+        * WebCore.xcodeproj/project.pbxproj:
+
 2012-05-01  Keishi Hattori  <[email protected]>
 
         datalist: Form control in a <datalist> should be barred from constraint validation

Modified: trunk/Source/WebCore/GNUmakefile.list.am (115786 => 115787)


--- trunk/Source/WebCore/GNUmakefile.list.am	2012-05-02 03:35:48 UTC (rev 115786)
+++ trunk/Source/WebCore/GNUmakefile.list.am	2012-05-02 03:38:23 UTC (rev 115787)
@@ -5473,6 +5473,8 @@
 webcore_sources += \
 	Source/WebCore/Modules/webaudio/AsyncAudioDecoder.cpp \
 	Source/WebCore/Modules/webaudio/AsyncAudioDecoder.h \
+	Source/WebCore/Modules/webaudio/AudioBasicInspectorNode.cpp \
+	Source/WebCore/Modules/webaudio/AudioBasicInspectorNode.h \
 	Source/WebCore/Modules/webaudio/AudioBasicProcessorNode.cpp \
 	Source/WebCore/Modules/webaudio/AudioBasicProcessorNode.h \
 	Source/WebCore/Modules/webaudio/AudioBuffer.cpp \

Added: trunk/Source/WebCore/Modules/webaudio/AudioBasicInspectorNode.cpp (0 => 115787)


--- trunk/Source/WebCore/Modules/webaudio/AudioBasicInspectorNode.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/webaudio/AudioBasicInspectorNode.cpp	2012-05-02 03:38:23 UTC (rev 115787)
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012, Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "AudioBasicInspectorNode.h"
+
+#include "AudioContext.h"
+#include "AudioNodeInput.h"
+#include "AudioNodeOutput.h"
+
+namespace WebCore {
+
+AudioBasicInspectorNode::AudioBasicInspectorNode(AudioContext* context, float sampleRate)
+    : AudioNode(context, sampleRate)
+    , m_needAutomaticPull(false)
+{
+    addInput(adoptPtr(new AudioNodeInput(this)));
+    addOutput(adoptPtr(new AudioNodeOutput(this, 2)));
+}
+
+// We override pullInputs() as an optimization allowing this node to take advantage of in-place processing,
+// where the input is simply passed through unprocessed to the output.
+// Note: this only applies if the input and output channel counts match.
+void AudioBasicInspectorNode::pullInputs(size_t framesToProcess)
+{
+    // Render input stream - try to render directly into output bus for pass-through processing where process() doesn't need to do anything...
+    input(0)->pull(output(0)->bus(), framesToProcess);
+}
+
+void AudioBasicInspectorNode::connect(AudioNode* destination, unsigned outputIndex, unsigned inputIndex, ExceptionCode& ec)
+{
+    ASSERT(isMainThread());
+
+    AudioContext::AutoLocker locker(context());
+
+    AudioNode::connect(destination, outputIndex, inputIndex, ec);
+    updatePullStatus();
+}
+
+void AudioBasicInspectorNode::disconnect(unsigned outputIndex, ExceptionCode& ec)
+{
+    ASSERT(isMainThread());
+
+    AudioContext::AutoLocker locker(context());
+
+    AudioNode::disconnect(outputIndex, ec);
+    updatePullStatus();
+}
+
+void AudioBasicInspectorNode::checkNumberOfChannelsForInput(AudioNodeInput* input)
+{
+    ASSERT(context()->isAudioThread() && context()->isGraphOwner());
+
+    ASSERT(input == this->input(0));
+    if (input != this->input(0))
+        return;
+
+    unsigned numberOfChannels = input->numberOfChannels();
+
+    if (numberOfChannels != output(0)->numberOfChannels()) {
+        // This will propagate the channel count to any nodes connected further downstream in the graph.
+        output(0)->setNumberOfChannels(numberOfChannels);
+    }
+
+    AudioNode::checkNumberOfChannelsForInput(input);
+
+    updatePullStatus();
+}
+
+void AudioBasicInspectorNode::updatePullStatus()
+{
+    ASSERT(context()->isGraphOwner());
+
+    if (output(0)->isConnected()) {
+        // When an AudioBasicInspectorNode is connected to a downstream node, it will get pulled by the
+        // downstream node, thus remove it from the context's automatic pull list.
+        if (m_needAutomaticPull) {
+            context()->removeAutomaticPullNode(this);
+            m_needAutomaticPull = false;
+        }
+    } else {
+        unsigned numberOfInputConnections = input(0)->numberOfRenderingConnections();
+        if (numberOfInputConnections && !m_needAutomaticPull) {
+            // When an AudioBasicInspectorNode is not connected to any downstream node while still connected from
+            // upstream node(s), add it to the context's automatic pull list.
+            context()->addAutomaticPullNode(this);
+            m_needAutomaticPull = true;
+        } else if (!numberOfInputConnections && m_needAutomaticPull) {
+            // The AudioBasicInspectorNode is connected to nothing, remove it from the context's automatic pull list.
+            context()->removeAutomaticPullNode(this);
+            m_needAutomaticPull = false;
+        }
+    }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)

Added: trunk/Source/WebCore/Modules/webaudio/AudioBasicInspectorNode.h (0 => 115787)


--- trunk/Source/WebCore/Modules/webaudio/AudioBasicInspectorNode.h	                        (rev 0)
+++ trunk/Source/WebCore/Modules/webaudio/AudioBasicInspectorNode.h	2012-05-02 03:38:23 UTC (rev 115787)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2012, Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AudioBasicInspectorNode_h
+#define AudioBasicInspectorNode_h
+
+#include "AudioNode.h"
+
+namespace WebCore {
+
+// AudioBasicInspectorNode is an AudioNode with one input and one output where the output might not necessarily connect to another node's input.
+// If the output is not connected to any other node, then the AudioBasicInspectorNode's processIfNecessary() function will be called automatically by
+// AudioContext before the end of each render quantum so that it can inspect the audio stream.
+class AudioBasicInspectorNode : public AudioNode {
+public:
+    AudioBasicInspectorNode(AudioContext*, float sampleRate);
+
+    // AudioNode
+    virtual void pullInputs(size_t framesToProcess);
+    virtual void connect(AudioNode*, unsigned outputIndex, unsigned inputIndex, ExceptionCode&);
+    virtual void disconnect(unsigned outputIndex, ExceptionCode&);
+    virtual void checkNumberOfChannelsForInput(AudioNodeInput*);
+
+private:
+    void updatePullStatus();
+    bool m_needAutomaticPull; // When setting to true, AudioBasicInspectorNode will be pulled automaticlly by AudioContext before the end of each render quantum.
+};
+
+} // namespace WebCore
+
+#endif // AudioBasicInspectorNode_h

Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp (115786 => 115787)


--- trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp	2012-05-02 03:35:48 UTC (rev 115786)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp	2012-05-02 03:38:23 UTC (rev 115787)
@@ -140,6 +140,7 @@
     , m_document(document)
     , m_destinationNode(0)
     , m_isDeletionScheduled(false)
+    , m_automaticPullNodesNeedUpdating(false)
     , m_connectionCount(0)
     , m_audioThread(0)
     , m_graphOwnerThread(UndefinedThreadIdentifier)
@@ -164,6 +165,7 @@
     , m_isAudioThreadFinished(false)
     , m_document(document)
     , m_destinationNode(0)
+    , m_automaticPullNodesNeedUpdating(false)
     , m_connectionCount(0)
     , m_audioThread(0)
     , m_graphOwnerThread(UndefinedThreadIdentifier)
@@ -200,6 +202,8 @@
     ASSERT(!m_nodesToDelete.size());
     ASSERT(!m_referencedNodes.size());
     ASSERT(!m_finishedNodes.size());
+    ASSERT(!m_automaticPullNodes.size());
+    ASSERT(!m_renderingAutomaticPullNodes.size());
 }
 
 void AudioContext::lazyInitialize()
@@ -662,7 +666,9 @@
         // Fixup the state of any dirty AudioNodeInputs and AudioNodeOutputs.
         handleDirtyAudioNodeInputs();
         handleDirtyAudioNodeOutputs();
-        
+
+        updateAutomaticPullNodes();
+
         if (mustReleaseLock)
             unlock();
     }
@@ -690,7 +696,9 @@
         // Fixup the state of any dirty AudioNodeInputs and AudioNodeOutputs.
         handleDirtyAudioNodeInputs();
         handleDirtyAudioNodeOutputs();
-        
+
+        updateAutomaticPullNodes();
+
         if (mustReleaseLock)
             unlock();
     }
@@ -712,6 +720,12 @@
 {
     ASSERT(isGraphOwner());
     m_nodesToDelete.append(node);
+
+    // This is probably the best time for us to remove the node from automatic pull list,
+    // since all connections are gone and we hold the graph lock. Then when handlePostRenderTasks()
+    // gets a chance to schedule the deletion work, updateAutomaticPullNodes() also gets a chance to
+    // modify m_renderingAutomaticPullNodes.
+    removeAutomaticPullNode(node);
 }
 
 void AudioContext::scheduleNodeDeletion()
@@ -803,6 +817,52 @@
     m_dirtyAudioNodeOutputs.clear();
 }
 
+void AudioContext::addAutomaticPullNode(AudioNode* node)
+{
+    ASSERT(isGraphOwner());
+
+    if (!m_automaticPullNodes.contains(node)) {
+        m_automaticPullNodes.add(node);
+        m_automaticPullNodesNeedUpdating = true;
+    }
+}
+
+void AudioContext::removeAutomaticPullNode(AudioNode* node)
+{
+    ASSERT(isGraphOwner());
+
+    if (m_automaticPullNodes.contains(node)) {
+        m_automaticPullNodes.remove(node);
+        m_automaticPullNodesNeedUpdating = true;
+    }
+}
+
+void AudioContext::updateAutomaticPullNodes()
+{
+    ASSERT(isGraphOwner());
+
+    if (m_automaticPullNodesNeedUpdating) {
+        // Copy from m_automaticPullNodes to m_renderingAutomaticPullNodes.
+        m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size());
+
+        unsigned j = 0;
+        for (HashSet<AudioNode*>::iterator i = m_automaticPullNodes.begin(); i != m_automaticPullNodes.end(); ++i, ++j) {
+            AudioNode* output = *i;
+            m_renderingAutomaticPullNodes[j] = output;
+        }
+
+        m_automaticPullNodesNeedUpdating = false;
+    }
+}
+
+void AudioContext::processAutomaticPullNodes(size_t framesToProcess)
+{
+    ASSERT(isAudioThread());
+
+    for (unsigned i = 0; i < m_renderingAutomaticPullNodes.size(); ++i)
+        m_renderingAutomaticPullNodes[i]->processIfNecessary(framesToProcess);
+}
+
 const AtomicString& AudioContext::interfaceName() const
 {
     return eventNames().interfaceForAudioContext;

Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.h (115786 => 115787)


--- trunk/Source/WebCore/Modules/webaudio/AudioContext.h	2012-05-02 03:35:48 UTC (rev 115786)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.h	2012-05-02 03:38:23 UTC (rev 115787)
@@ -148,7 +148,15 @@
     // We schedule deletion of all marked nodes at the end of each realtime render quantum.
     void markForDeletion(AudioNode*);
     void deleteMarkedNodes();
-    
+
+    // AudioContext can pull node(s) at the end of each render quantum even when they are not connected to any downstream nodes.
+    // These two methods are called by the nodes who want to add/remove themselves into/from the automatic pull lists.
+    void addAutomaticPullNode(AudioNode*);
+    void removeAutomaticPullNode(AudioNode*);
+
+    // Called right before handlePostRenderTasks() to handle nodes which need to be pulled even when they are not connected to anything.
+    void processAutomaticPullNodes(size_t framesToProcess);
+
     // Keeps track of the number of connections made.
     void incrementConnectionCount()
     {
@@ -281,6 +289,14 @@
     void handleDirtyAudioNodeInputs();
     void handleDirtyAudioNodeOutputs();
 
+    // For the sake of thread safety, we maintain a seperate Vector of automatic pull nodes for rendering in m_renderingAutomaticPullNodes.
+    // It will be copied from m_automaticPullNodes by updateAutomaticPullNodes() at the very start or end of the rendering quantum.
+    HashSet<AudioNode*> m_automaticPullNodes;
+    Vector<AudioNode*> m_renderingAutomaticPullNodes;
+    // m_automaticPullNodesNeedUpdating keeps track if m_automaticPullNodes is modified.
+    bool m_automaticPullNodesNeedUpdating;
+    void updateAutomaticPullNodes();
+
     unsigned m_connectionCount;
 
     // Graph locking.

Modified: trunk/Source/WebCore/Modules/webaudio/AudioDestinationNode.cpp (115786 => 115787)


--- trunk/Source/WebCore/Modules/webaudio/AudioDestinationNode.cpp	2012-05-02 03:35:48 UTC (rev 115786)
+++ trunk/Source/WebCore/Modules/webaudio/AudioDestinationNode.cpp	2012-05-02 03:38:23 UTC (rev 115787)
@@ -80,6 +80,9 @@
         destinationBus->copyFrom(*renderedBus);
     }
 
+    // Process nodes which need a little extra help because they are not connected to anything, but still need to process.
+    context()->processAutomaticPullNodes(numberOfFrames);
+
     // Let the context take care of any business at the end of each render quantum.
     context()->handlePostRenderTasks();
     

Modified: trunk/Source/WebCore/Modules/webaudio/AudioNode.h (115786 => 115787)


--- trunk/Source/WebCore/Modules/webaudio/AudioNode.h	2012-05-02 03:35:48 UTC (rev 115786)
+++ trunk/Source/WebCore/Modules/webaudio/AudioNode.h	2012-05-02 03:38:23 UTC (rev 115787)
@@ -116,9 +116,9 @@
     AudioNodeOutput* output(unsigned);
 
     // Called from main thread by corresponding _javascript_ methods.
-    void connect(AudioNode*, unsigned outputIndex, unsigned inputIndex, ExceptionCode&);
+    virtual void connect(AudioNode*, unsigned outputIndex, unsigned inputIndex, ExceptionCode&);
     void connect(AudioParam*, unsigned outputIndex, ExceptionCode&);
-    void disconnect(unsigned outputIndex, ExceptionCode&);
+    virtual void disconnect(unsigned outputIndex, ExceptionCode&);
 
     virtual float sampleRate() const { return m_sampleRate; }
 

Modified: trunk/Source/WebCore/Modules/webaudio/AudioNodeOutput.h (115786 => 115787)


--- trunk/Source/WebCore/Modules/webaudio/AudioNodeOutput.h	2012-05-02 03:35:48 UTC (rev 115786)
+++ trunk/Source/WebCore/Modules/webaudio/AudioNodeOutput.h	2012-05-02 03:38:23 UTC (rev 115787)
@@ -72,6 +72,8 @@
     unsigned numberOfChannels() const { return m_numberOfChannels; }
     bool isChannelCountKnown() const { return numberOfChannels() > 0; }
 
+    bool isConnected() { return fanOutCount() > 0 || paramFanOutCount() > 0; }
+
     // Disable/Enable happens when there are still _javascript_ references to a node, but it has otherwise "finished" its work.
     // For example, when a note has finished playing.  It is kept around, because it may be played again at a later time.
     // They must be called with the context's graph lock.

Modified: trunk/Source/WebCore/Modules/webaudio/RealtimeAnalyserNode.cpp (115786 => 115787)


--- trunk/Source/WebCore/Modules/webaudio/RealtimeAnalyserNode.cpp	2012-05-02 03:35:48 UTC (rev 115786)
+++ trunk/Source/WebCore/Modules/webaudio/RealtimeAnalyserNode.cpp	2012-05-02 03:38:23 UTC (rev 115787)
@@ -35,7 +35,7 @@
 namespace WebCore {
 
 RealtimeAnalyserNode::RealtimeAnalyserNode(AudioContext* context, float sampleRate)
-    : AudioNode(context, sampleRate)
+    : AudioBasicInspectorNode(context, sampleRate)
 {
     addInput(adoptPtr(new AudioNodeInput(this)));
     addOutput(adoptPtr(new AudioNodeOutput(this, 2)));
@@ -70,15 +70,6 @@
         outputBus->copyFrom(*inputBus);
 }
 
-// We override pullInputs() as an optimization allowing this node to take advantage of in-place processing,
-// where the input is simply passed through unprocessed to the output.
-// Note: this only applies if the input and output channel counts match.
-void RealtimeAnalyserNode::pullInputs(size_t framesToProcess)
-{
-    // Render input stream - try to render directly into output bus for pass-through processing where process() doesn't need to do anything...
-    input(0)->pull(output(0)->bus(), framesToProcess);
-}
-
 void RealtimeAnalyserNode::reset()
 {
     m_analyser.reset();

Modified: trunk/Source/WebCore/Modules/webaudio/RealtimeAnalyserNode.h (115786 => 115787)


--- trunk/Source/WebCore/Modules/webaudio/RealtimeAnalyserNode.h	2012-05-02 03:35:48 UTC (rev 115786)
+++ trunk/Source/WebCore/Modules/webaudio/RealtimeAnalyserNode.h	2012-05-02 03:38:23 UTC (rev 115787)
@@ -25,13 +25,13 @@
 #ifndef RealtimeAnalyserNode_h
 #define RealtimeAnalyserNode_h
 
-#include "AudioNode.h"
+#include "AudioBasicInspectorNode.h"
 #include "RealtimeAnalyser.h"
 #include <wtf/Forward.h>
 
 namespace WebCore {
 
-class RealtimeAnalyserNode : public AudioNode {
+class RealtimeAnalyserNode : public AudioBasicInspectorNode {
 public:
     static PassRefPtr<RealtimeAnalyserNode> create(AudioContext* context, float sampleRate)
     {
@@ -42,7 +42,6 @@
     
     // AudioNode
     virtual void process(size_t framesToProcess);
-    virtual void pullInputs(size_t framesToProcess);
     virtual void reset();
 
     // _javascript_ bindings

Modified: trunk/Source/WebCore/WebCore.gypi (115786 => 115787)


--- trunk/Source/WebCore/WebCore.gypi	2012-05-02 03:35:48 UTC (rev 115786)
+++ trunk/Source/WebCore/WebCore.gypi	2012-05-02 03:38:23 UTC (rev 115787)
@@ -1557,6 +1557,8 @@
             'Modules/speech/SpeechRecognitionResult.h',
             'Modules/speech/SpeechRecognitionResultList.cpp',
             'Modules/speech/SpeechRecognitionResultList.h',
+            'Modules/webaudio/AudioBasicInspectorNode.cpp',
+            'Modules/webaudio/AudioBasicInspectorNode.h',
             'Modules/webaudio/AudioBasicProcessorNode.cpp',
             'Modules/webaudio/AudioBasicProcessorNode.h',
             'Modules/webaudio/AudioBuffer.cpp',

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (115786 => 115787)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2012-05-02 03:35:48 UTC (rev 115786)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2012-05-02 03:38:23 UTC (rev 115787)
@@ -6292,6 +6292,8 @@
 		FD581FAF1520F91F003A7A75 /* Oscillator.h in Headers */ = {isa = PBXBuildFile; fileRef = FD581FAC1520F91F003A7A75 /* Oscillator.h */; };
 		FD581FB41520F93B003A7A75 /* WaveTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FD581FB11520F93B003A7A75 /* WaveTable.cpp */; };
 		FD581FB51520F93B003A7A75 /* WaveTable.h in Headers */ = {isa = PBXBuildFile; fileRef = FD581FB21520F93B003A7A75 /* WaveTable.h */; };
+		FD629EA3154B47160006D026 /* AudioBasicInspectorNode.h in Headers */ = {isa = PBXBuildFile; fileRef = FD629EA1154B47160006D026 /* AudioBasicInspectorNode.h */; };
+		FD629EA4154B47160006D026 /* AudioBasicInspectorNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FD629EA2154B47160006D026 /* AudioBasicInspectorNode.cpp */; };
 		FD62F52E145898D80094B0ED /* AudioSourceProviderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = FD62F52D145898D80094B0ED /* AudioSourceProviderClient.h */; };
 		FD6ED2C3136B8E42003CF072 /* DynamicsCompressorNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FD6ED2C1136B8E42003CF072 /* DynamicsCompressorNode.cpp */; };
 		FD6ED2C4136B8E42003CF072 /* DynamicsCompressorNode.h in Headers */ = {isa = PBXBuildFile; fileRef = FD6ED2C2136B8E42003CF072 /* DynamicsCompressorNode.h */; };
@@ -13520,6 +13522,8 @@
 		FD581FB11520F93B003A7A75 /* WaveTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WaveTable.cpp; sourceTree = "<group>"; };
 		FD581FB21520F93B003A7A75 /* WaveTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WaveTable.h; sourceTree = "<group>"; };
 		FD581FB31520F93B003A7A75 /* WaveTable.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WaveTable.idl; sourceTree = "<group>"; };
+		FD629EA1154B47160006D026 /* AudioBasicInspectorNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioBasicInspectorNode.h; sourceTree = "<group>"; };
+		FD629EA2154B47160006D026 /* AudioBasicInspectorNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioBasicInspectorNode.cpp; sourceTree = "<group>"; };
 		FD62F52D145898D80094B0ED /* AudioSourceProviderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioSourceProviderClient.h; sourceTree = "<group>"; };
 		FD6ED2C1136B8E42003CF072 /* DynamicsCompressorNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DynamicsCompressorNode.cpp; sourceTree = "<group>"; };
 		FD6ED2C2136B8E42003CF072 /* DynamicsCompressorNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicsCompressorNode.h; sourceTree = "<group>"; };
@@ -21365,6 +21369,8 @@
 			children = (
 				FD5686C713AC180200B69C68 /* AsyncAudioDecoder.cpp */,
 				FD5686C813AC180200B69C68 /* AsyncAudioDecoder.h */,
+				FD629EA1154B47160006D026 /* AudioBasicInspectorNode.h */,
+				FD629EA2154B47160006D026 /* AudioBasicInspectorNode.cpp */,
 				FD315FAC12B0267500C1A359 /* AudioBasicProcessorNode.cpp */,
 				FD315FAD12B0267500C1A359 /* AudioBasicProcessorNode.h */,
 				FD315FAE12B0267500C1A359 /* AudioBuffer.cpp */,
@@ -24837,6 +24843,7 @@
 				FD8C46EC154608E700A5910C /* AudioScheduledSourceNode.h in Headers */,
 				71A57DF2154BE25C0009D120 /* SVGPathUtilities.h in Headers */,
 				78D02BC6154A18DF00B62D05 /* CSSPropertyAnimation.h in Headers */,
+				FD629EA3154B47160006D026 /* AudioBasicInspectorNode.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -27853,6 +27860,7 @@
 				FD8C46EB154608E700A5910C /* AudioScheduledSourceNode.cpp in Sources */,
 				71A57DF1154BE25C0009D120 /* SVGPathUtilities.cpp in Sources */,
 				78D02BC5154A18DF00B62D05 /* CSSPropertyAnimation.cpp in Sources */,
+				FD629EA4154B47160006D026 /* AudioBasicInspectorNode.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to