[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

crogers at google.com crogers at google.com
Wed Dec 22 13:41:46 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit c6e1a8d52cc469338f95cd7f037abe4f2ad105e8
Author: crogers at google.com <crogers at google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu Sep 23 17:49:52 2010 +0000

    2010-09-23  Chris Rogers  <crogers at google.com>
    
            Reviewed by Kenneth Russell.
    
            Add AudioContext files
            https://bugs.webkit.org/show_bug.cgi?id=44890
    
            No new tests since audio API is not yet implemented.
    
            * webaudio/AudioContext.cpp: Added.
            (WebCore::AudioContext::createAudioRequest):
            (WebCore::AudioContext::create):
            (WebCore::AudioContext::AudioContext):
            (WebCore::AudioContext::~AudioContext):
            (WebCore::AudioContext::lazyInitialize):
            (WebCore::AudioContext::uninitialize):
            (WebCore::AudioContext::isInitialized):
            (WebCore::AudioContext::isRunnable):
            (WebCore::AudioContext::stop):
            (WebCore::AudioContext::document):
            (WebCore::AudioContext::hasDocument):
            (WebCore::AudioContext::refBuffer):
            (WebCore::AudioContext::createBuffer):
            (WebCore::AudioContext::createBufferSource):
            (WebCore::AudioContext::createJavaScriptNode):
            (WebCore::AudioContext::createLowPass2Filter):
            (WebCore::AudioContext::createHighPass2Filter):
            (WebCore::AudioContext::createPanner):
            (WebCore::AudioContext::createConvolver):
            (WebCore::AudioContext::createAnalyser):
            (WebCore::AudioContext::createGainNode):
            (WebCore::AudioContext::createDelayNode):
            (WebCore::AudioContext::createChannelSplitter):
            (WebCore::AudioContext::createChannelMerger):
            (WebCore::AudioContext::notifyNodeFinishedProcessing):
            (WebCore::AudioContext::derefFinishedSourceNodes):
            (WebCore::AudioContext::refNode):
            (WebCore::AudioContext::derefNode):
            (WebCore::AudioContext::derefUnfinishedSourceNodes):
            (WebCore::AudioContext::lock):
            (WebCore::AudioContext::tryLock):
            (WebCore::AudioContext::unlock):
            (WebCore::AudioContext::isAudioThread):
            (WebCore::AudioContext::isGraphOwner):
            (WebCore::AudioContext::addDeferredFinishDeref):
            (WebCore::AudioContext::handlePostRenderTasks):
            (WebCore::AudioContext::handleDeferredFinishDerefs):
            (WebCore::AudioContext::markForDeletion):
            (WebCore::AudioContext::deleteMarkedNodes):
            * webaudio/AudioContext.h: Added.
            (WebCore::AudioContext::destination):
            (WebCore::AudioContext::currentTime):
            (WebCore::AudioContext::sampleRate):
            (WebCore::AudioContext::listener):
            (WebCore::AudioContext::temporaryMonoBus):
            (WebCore::AudioContext::temporaryStereoBus):
            (WebCore::AudioContext::incrementConnectionCount):
            (WebCore::AudioContext::connectionCount):
            (WebCore::AudioContext::setAudioThread):
            (WebCore::AudioContext::audioThread):
            (WebCore::AudioContext::isAudioThreadFinished):
            (WebCore::AudioContext::AutoLocker::AutoLocker):
            (WebCore::AudioContext::AutoLocker::~AutoLocker):
            (WebCore::AudioContext::RefInfo::RefInfo):
            * webaudio/AudioContext.idl: Added.
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@68163 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 9a39267..9ef07e9 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,69 @@
+2010-09-23  Chris Rogers  <crogers at google.com>
+
+        Reviewed by Kenneth Russell.
+
+        Add AudioContext files
+        https://bugs.webkit.org/show_bug.cgi?id=44890
+
+        No new tests since audio API is not yet implemented.
+
+        * webaudio/AudioContext.cpp: Added.
+        (WebCore::AudioContext::createAudioRequest):
+        (WebCore::AudioContext::create):
+        (WebCore::AudioContext::AudioContext):
+        (WebCore::AudioContext::~AudioContext):
+        (WebCore::AudioContext::lazyInitialize):
+        (WebCore::AudioContext::uninitialize):
+        (WebCore::AudioContext::isInitialized):
+        (WebCore::AudioContext::isRunnable):
+        (WebCore::AudioContext::stop):
+        (WebCore::AudioContext::document):
+        (WebCore::AudioContext::hasDocument):
+        (WebCore::AudioContext::refBuffer):
+        (WebCore::AudioContext::createBuffer):
+        (WebCore::AudioContext::createBufferSource):
+        (WebCore::AudioContext::createJavaScriptNode):
+        (WebCore::AudioContext::createLowPass2Filter):
+        (WebCore::AudioContext::createHighPass2Filter):
+        (WebCore::AudioContext::createPanner):
+        (WebCore::AudioContext::createConvolver):
+        (WebCore::AudioContext::createAnalyser):
+        (WebCore::AudioContext::createGainNode):
+        (WebCore::AudioContext::createDelayNode):
+        (WebCore::AudioContext::createChannelSplitter):
+        (WebCore::AudioContext::createChannelMerger):
+        (WebCore::AudioContext::notifyNodeFinishedProcessing):
+        (WebCore::AudioContext::derefFinishedSourceNodes):
+        (WebCore::AudioContext::refNode):
+        (WebCore::AudioContext::derefNode):
+        (WebCore::AudioContext::derefUnfinishedSourceNodes):
+        (WebCore::AudioContext::lock):
+        (WebCore::AudioContext::tryLock):
+        (WebCore::AudioContext::unlock):
+        (WebCore::AudioContext::isAudioThread):
+        (WebCore::AudioContext::isGraphOwner):
+        (WebCore::AudioContext::addDeferredFinishDeref):
+        (WebCore::AudioContext::handlePostRenderTasks):
+        (WebCore::AudioContext::handleDeferredFinishDerefs):
+        (WebCore::AudioContext::markForDeletion):
+        (WebCore::AudioContext::deleteMarkedNodes):
+        * webaudio/AudioContext.h: Added.
+        (WebCore::AudioContext::destination):
+        (WebCore::AudioContext::currentTime):
+        (WebCore::AudioContext::sampleRate):
+        (WebCore::AudioContext::listener):
+        (WebCore::AudioContext::temporaryMonoBus):
+        (WebCore::AudioContext::temporaryStereoBus):
+        (WebCore::AudioContext::incrementConnectionCount):
+        (WebCore::AudioContext::connectionCount):
+        (WebCore::AudioContext::setAudioThread):
+        (WebCore::AudioContext::audioThread):
+        (WebCore::AudioContext::isAudioThreadFinished):
+        (WebCore::AudioContext::AutoLocker::AutoLocker):
+        (WebCore::AudioContext::AutoLocker::~AutoLocker):
+        (WebCore::AudioContext::RefInfo::RefInfo):
+        * webaudio/AudioContext.idl: Added.
+
 2010-09-23  Jeremy Orlow  <jorlow at chromium.org>
 
         Reviewed by Steve Block.
diff --git a/WebCore/webaudio/AudioContext.cpp b/WebCore/webaudio/AudioContext.cpp
new file mode 100644
index 0000000..6ca8ee1
--- /dev/null
+++ b/WebCore/webaudio/AudioContext.cpp
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2010 Google Inc. 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "AudioContext.h"
+
+#include "AudioBuffer.h"
+#include "AudioBufferSourceNode.h"
+#include "AudioChannelMerger.h"
+#include "AudioChannelSplitter.h"
+#include "AudioGainNode.h"
+#include "AudioListener.h"
+#include "AudioPannerNode.h"
+#include "CachedAudio.h"
+#include "ConvolverNode.h"
+#include "DelayNode.h"
+#include "Document.h"
+#include "HRTFDatabaseLoader.h"
+#include "HRTFPanner.h"
+#include "HTMLNames.h"
+#include "HighPass2FilterNode.h"
+#include "JavaScriptAudioNode.h"
+#include "LowPass2FilterNode.h"
+#include "PlatformString.h"
+#include "RealtimeAnalyserNode.h"
+
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
+
+// FIXME: check the proper way to reference an undefined thread ID
+const int UndefinedThreadIdentifier = 0xffffffff;
+ 
+namespace WebCore {
+
+PassRefPtr<CachedAudio> AudioContext::createAudioRequest(const String &url, bool mixToMono)
+{
+    lazyInitialize();
+
+    // Convert relative URL to absolute
+    KURL completedURL = document()->completeURL(url);
+    String completedURLString = completedURL.string();
+
+    RefPtr<CachedAudio> cachedAudio = CachedAudio::create(completedURLString, this, document(), sampleRate(), mixToMono);
+    CachedAudio* c = cachedAudio.get();
+
+    m_cachedAudioReferences.append(c);
+
+    return cachedAudio;
+}
+
+PassRefPtr<AudioContext> AudioContext::create(Document* document)
+{
+    return adoptRef(new AudioContext(document));
+}
+
+AudioContext::AudioContext(Document* document)
+    : ActiveDOMObject(document, this)
+    , m_isInitialized(false)
+    , m_isAudioThreadFinished(false)
+    , m_document(document)
+    , m_destinationNode(0)
+    , m_connectionCount(0)
+    , m_audioThread(0)
+    , m_graphOwnerThread(UndefinedThreadIdentifier)
+{
+    // Note: because adoptRef() won't be called until we leave this constructor, but code in this constructor needs to reference this context,
+    // relax the check.
+    relaxAdoptionRequirement();
+    
+    m_destinationNode = AudioDestinationNode::create(this);
+    m_listener = AudioListener::create();
+    m_temporaryMonoBus = adoptPtr(new AudioBus(1, AudioNode::ProcessingSizeInFrames));
+    m_temporaryStereoBus = adoptPtr(new AudioBus(2, AudioNode::ProcessingSizeInFrames));
+
+    // This sets in motion an asynchronous loading mechanism on another thread.
+    // We can check hrtfDatabaseLoader()->isLoaded() to find out whether or not it has been fully loaded.
+    // It's not that useful to have a callback function for this since the audio thread automatically starts rendering on the graph
+    // when this has finished (see AudioDestinationNode).
+    hrtfDatabaseLoader()->loadAsynchronously(sampleRate());
+}
+
+AudioContext::~AudioContext()
+{
+#if DEBUG_AUDIONODE_REFERENCES
+    printf("%p: AudioContext::~AudioContext()\n", this);
+#endif    
+    // AudioNodes keep a reference to their context, so there should be no way to be in the destructor if there are still AudioNodes around.
+    ASSERT(!m_nodesToDelete.size());
+    ASSERT(!m_referencedNodes.size());
+    ASSERT(!m_finishedNodes.size());
+}
+
+void AudioContext::lazyInitialize()
+{
+    if (!m_isInitialized) {
+        // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
+        ASSERT(!m_isAudioThreadFinished);
+        if (!m_isAudioThreadFinished) {
+            if (m_destinationNode.get()) {
+                // This starts the audio thread.  The destination node's provideInput() method will now be called repeatedly to render audio.
+                // Each time provideInput() is called, a portion of the audio stream is rendered.  Let's call this time period a "render quantum".
+                m_destinationNode->initialize();
+            }
+            m_isInitialized = true;
+        }
+    }
+}
+
+void AudioContext::uninitialize()
+{
+    if (m_isInitialized) {    
+        // This stops the audio thread and all audio rendering.
+        m_destinationNode->uninitialize();
+
+        // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
+        m_isAudioThreadFinished = true;
+
+        // We have to release our reference to the destination node before the context will ever be deleted since the destination node holds a reference to the context.
+        m_destinationNode.clear();
+        
+        // Get rid of the sources which may still be playing.
+        derefUnfinishedSourceNodes();
+        
+        // Because the AudioBuffers are garbage collected, we can't delete them here.
+        // Instead, at least release the potentially large amount of allocated memory for the audio data.
+        // Note that we do this *after* the context is uninitialized and stops processing audio.
+        for (unsigned i = 0; i < m_allocatedBuffers.size(); ++i)
+            m_allocatedBuffers[i]->releaseMemory();
+        m_allocatedBuffers.clear();
+    
+        m_isInitialized = false;
+    }
+}
+
+bool AudioContext::isInitialized() const
+{
+    return m_isInitialized;
+}
+
+bool AudioContext::isRunnable() const
+{
+    if (!isInitialized())
+        return false;
+    
+    // Check with the HRTF spatialization system to see if it's finished loading.
+    return hrtfDatabaseLoader()->isLoaded();
+}
+
+void AudioContext::stop()
+{
+    m_document = 0; // document is going away
+    uninitialize();
+}
+
+Document* AudioContext::document()
+{
+    ASSERT(m_document);
+    return m_document;
+}
+
+bool AudioContext::hasDocument()
+{
+    return m_document;
+}
+
+void AudioContext::refBuffer(PassRefPtr<AudioBuffer> buffer)
+{
+    m_allocatedBuffers.append(buffer);
+}
+
+PassRefPtr<AudioBuffer> AudioContext::createBuffer(unsigned numberOfChannels, size_t numberOfFrames, double sampleRate)
+{
+    return AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
+}
+
+PassRefPtr<AudioBufferSourceNode> AudioContext::createBufferSource()
+{
+    ASSERT(isMainThread());
+    lazyInitialize();
+    RefPtr<AudioBufferSourceNode> node = AudioBufferSourceNode::create(this, m_destinationNode->sampleRate());
+
+    refNode(node.get()); // context keeps reference until source has finished playing
+    return node;
+}
+
+PassRefPtr<JavaScriptAudioNode> AudioContext::createJavaScriptNode(size_t bufferSize)
+{
+    ASSERT(isMainThread());
+    lazyInitialize();
+    RefPtr<JavaScriptAudioNode> node = JavaScriptAudioNode::create(this, m_destinationNode->sampleRate(), bufferSize);
+
+    refNode(node.get()); // context keeps reference until we stop making javascript rendering callbacks
+    return node;
+}
+
+PassRefPtr<LowPass2FilterNode> AudioContext::createLowPass2Filter()
+{
+    ASSERT(isMainThread());
+    lazyInitialize();
+    return LowPass2FilterNode::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<HighPass2FilterNode> AudioContext::createHighPass2Filter()
+{
+    ASSERT(isMainThread());
+    lazyInitialize();
+    return HighPass2FilterNode::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<AudioPannerNode> AudioContext::createPanner()
+{
+    ASSERT(isMainThread());
+    lazyInitialize();
+    return AudioPannerNode::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<ConvolverNode> AudioContext::createConvolver()
+{
+    ASSERT(isMainThread());
+    lazyInitialize();
+    return ConvolverNode::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<RealtimeAnalyserNode> AudioContext::createAnalyser()
+{
+    ASSERT(isMainThread());
+    lazyInitialize();
+    return RealtimeAnalyserNode::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<AudioGainNode> AudioContext::createGainNode()
+{
+    ASSERT(isMainThread());
+    lazyInitialize();
+    return AudioGainNode::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<DelayNode> AudioContext::createDelayNode()
+{
+    ASSERT(isMainThread());
+    lazyInitialize();
+    return DelayNode::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<AudioChannelSplitter> AudioContext::createChannelSplitter()
+{
+    ASSERT(isMainThread());
+    lazyInitialize();
+    return AudioChannelSplitter::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<AudioChannelMerger> AudioContext::createChannelMerger()
+{
+    ASSERT(isMainThread());
+    lazyInitialize();
+    return AudioChannelMerger::create(this, m_destinationNode->sampleRate());
+}
+
+void AudioContext::notifyNodeFinishedProcessing(AudioNode* node)
+{
+    ASSERT(isAudioThread());
+    m_finishedNodes.append(node);
+}
+
+void AudioContext::derefFinishedSourceNodes()
+{
+    ASSERT(isGraphOwner());
+    ASSERT(isAudioThread() || isAudioThreadFinished());
+    for (unsigned i = 0; i < m_finishedNodes.size(); i++)
+        derefNode(m_finishedNodes[i]);
+
+    m_finishedNodes.clear();
+}
+
+void AudioContext::refNode(AudioNode* node)
+{
+    ASSERT(isMainThread());
+    AutoLocker locker(this);
+    
+    node->ref(AudioNode::RefTypeConnection);
+    m_referencedNodes.append(node);
+}
+
+void AudioContext::derefNode(AudioNode* node)
+{
+    ASSERT(isGraphOwner());
+    
+    node->deref(AudioNode::RefTypeConnection);
+
+    for (unsigned i = 0; i < m_referencedNodes.size(); ++i) {
+        if (node == m_referencedNodes[i]) {
+            m_referencedNodes.remove(i);
+            break;
+        }
+    }
+}
+
+void AudioContext::derefUnfinishedSourceNodes()
+{
+    ASSERT(isMainThread() && isAudioThreadFinished());
+    for (unsigned i = 0; i < m_referencedNodes.size(); ++i)
+        m_referencedNodes[i]->deref(AudioNode::RefTypeConnection);
+
+    m_referencedNodes.clear();
+}
+
+void AudioContext::lock(bool& mustReleaseLock)
+{
+    // Don't allow regular lock in real-time audio thread.
+    ASSERT(isMainThread());
+
+    ThreadIdentifier thisThread = currentThread();
+
+    if (thisThread == m_graphOwnerThread) {
+        // We already have the lock.
+        mustReleaseLock = false;
+    } else {
+        // Acquire the lock.
+        m_contextGraphMutex.lock();
+        mustReleaseLock = true;
+    }
+
+    m_graphOwnerThread = thisThread;
+}
+
+bool AudioContext::tryLock(bool& mustReleaseLock)
+{
+    ThreadIdentifier thisThread = currentThread();
+    bool isAudioThread = thisThread == audioThread();
+
+    // Try to catch cases of using try lock on main thread - it should use regular lock.
+    ASSERT(isAudioThread || isAudioThreadFinished());
+    
+    if (!isAudioThread) {
+        // In release build treat tryLock() as lock() (since above ASSERT(isAudioThread) never fires) - this is the best we can do.
+        lock(mustReleaseLock);
+        return true;
+    }
+    
+    bool hasLock;
+    
+    if (thisThread == m_graphOwnerThread) {
+        // Thread already has the lock.
+        hasLock = true;
+        mustReleaseLock = false;
+    } else {
+        // Don't already have the lock - try to acquire it.
+        hasLock = m_contextGraphMutex.tryLock();
+        
+        if (hasLock)
+            m_graphOwnerThread = thisThread;
+
+        mustReleaseLock = hasLock;
+    }
+    
+    return hasLock;
+}
+
+void AudioContext::unlock()
+{
+    ASSERT(currentThread() == m_graphOwnerThread);
+
+    m_graphOwnerThread = UndefinedThreadIdentifier;
+    m_contextGraphMutex.unlock();
+}
+
+bool AudioContext::isAudioThread()
+{
+    return currentThread() == m_audioThread;
+}
+
+bool AudioContext::isGraphOwner()
+{
+    return currentThread() == m_graphOwnerThread;
+}
+
+void AudioContext::addDeferredFinishDeref(AudioNode* node, AudioNode::RefType refType)
+{
+    ASSERT(isAudioThread());
+    m_deferredFinishDerefList.append(AudioContext::RefInfo(node, refType));
+}
+
+void AudioContext::handlePostRenderTasks()
+{
+    ASSERT(isAudioThread());
+    
+    // Must use a tryLock() here too.  Don't worry, the lock will very rarely be contended and this method is called frequently.
+    // The worst that can happen is that there will be some nodes which will take slightly longer than usual to be deleted or removed
+    // from the render graph (in which case they'll render silence).
+    bool mustReleaseLock;
+    if (tryLock(mustReleaseLock)) {
+        // Take care of finishing any derefs where the tryLock() failed previously.
+        handleDeferredFinishDerefs();
+
+        // Dynamically clean up nodes which are no longer needed.
+        derefFinishedSourceNodes();
+
+        // Finally actually delete.
+        deleteMarkedNodes();
+
+        if (mustReleaseLock)
+            unlock();
+    }
+}
+
+void AudioContext::handleDeferredFinishDerefs()
+{
+    ASSERT(isAudioThread());
+    for (unsigned i = 0; i < m_deferredFinishDerefList.size(); ++i) {
+        AudioNode* node = m_deferredFinishDerefList[i].m_node;
+        AudioNode::RefType refType = m_deferredFinishDerefList[i].m_refType;
+        node->finishDeref(refType);
+    }
+    
+    m_deferredFinishDerefList.clear();
+}
+
+void AudioContext::markForDeletion(AudioNode* node)
+{
+    ASSERT(isGraphOwner());
+    m_nodesToDelete.append(node);
+}
+
+void AudioContext::deleteMarkedNodes()
+{
+    ASSERT(isGraphOwner() || isAudioThreadFinished());
+
+    // Note: deleting an AudioNode can cause m_nodesToDelete to grow.
+    while (size_t n = m_nodesToDelete.size()) {
+        AudioNode* node = m_nodesToDelete[n - 1];
+        m_nodesToDelete.removeLast();
+        delete node;
+    }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/WebCore/webaudio/AudioContext.h b/WebCore/webaudio/AudioContext.h
new file mode 100644
index 0000000..f175bfe
--- /dev/null
+++ b/WebCore/webaudio/AudioContext.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2010 Google Inc. 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 AudioContext_h
+#define AudioContext_h
+
+#include "ActiveDOMObject.h"
+#include "AudioBus.h"
+#include "AudioDestinationNode.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Threading.h>
+#include <wtf/Vector.h>
+#include <wtf/text/AtomicStringHash.h>
+
+namespace WebCore {
+
+class AudioBuffer;
+class AudioBufferSourceNode;
+class AudioChannelMerger;
+class AudioChannelSplitter;
+class AudioGainNode;
+class AudioPannerNode;
+class AudioListener;
+class CachedAudio;
+class DelayNode;
+class Document;
+class LowPass2FilterNode;
+class HighPass2FilterNode;
+class ConvolverNode;
+class RealtimeAnalyserNode;
+class JavaScriptAudioNode;
+
+// AudioContext is the cornerstone of the web audio API and all AudioNodes are created from it.
+// For thread safety between the audio thread and the main thread, it has a rendering graph locking mechanism. 
+
+class AudioContext : public ActiveDOMObject, public RefCounted<AudioContext> {
+public:
+    static PassRefPtr<AudioContext> create(Document*);
+
+    virtual ~AudioContext();
+
+    bool isInitialized() const;
+
+    // Returns true when initialize() was called AND all asynchronous initialization has completed.
+    bool isRunnable() const;
+
+    // Document notification
+    virtual void stop();
+
+    Document* document(); // ASSERTs if document no longer exists.
+    bool hasDocument();
+
+    AudioDestinationNode* destination() { return m_destinationNode.get(); }
+    double currentTime() { return m_destinationNode->currentTime(); }
+    double sampleRate() { return m_destinationNode->sampleRate(); }
+
+    PassRefPtr<AudioBuffer> createBuffer(unsigned numberOfChannels, size_t numberOfFrames, double sampleRate);
+
+    PassRefPtr<CachedAudio> createAudioRequest(const String &url, bool mixToMono);
+
+    // Keep track of this buffer so we can release memory after the context is shut down...
+    void refBuffer(PassRefPtr<AudioBuffer> buffer);
+
+    AudioListener* listener() { return m_listener.get(); }
+
+    // The AudioNode create methods are called on the main thread (from JavaScript).
+    PassRefPtr<AudioBufferSourceNode> createBufferSource();
+    PassRefPtr<AudioGainNode> createGainNode();
+    PassRefPtr<DelayNode> createDelayNode();
+    PassRefPtr<LowPass2FilterNode> createLowPass2Filter();
+    PassRefPtr<HighPass2FilterNode> createHighPass2Filter();
+    PassRefPtr<AudioPannerNode> createPanner();
+    PassRefPtr<ConvolverNode> createConvolver();
+    PassRefPtr<RealtimeAnalyserNode> createAnalyser();
+    PassRefPtr<JavaScriptAudioNode> createJavaScriptNode(size_t bufferSize);
+    PassRefPtr<AudioChannelSplitter> createChannelSplitter();
+    PassRefPtr<AudioChannelMerger> createChannelMerger();
+
+    AudioBus* temporaryMonoBus() { return m_temporaryMonoBus.get(); }
+    AudioBus* temporaryStereoBus() { return m_temporaryStereoBus.get(); }
+
+    // When a source node has no more processing to do (has finished playing), then it tells the context to dereference it.
+    void notifyNodeFinishedProcessing(AudioNode*);
+
+    // Called at the end of each render quantum.
+    void handlePostRenderTasks();
+
+    // Called periodically at the end of each render quantum to dereference finished source nodes.
+    void derefFinishedSourceNodes();
+
+    // We reap all marked nodes at the end of each realtime render quantum in deleteMarkedNodes().
+    void markForDeletion(AudioNode*);
+    void deleteMarkedNodes();
+
+    // Keeps track of the number of connections made.
+    void incrementConnectionCount()
+    {
+        ASSERT(isMainThread());
+        m_connectionCount++;
+    }
+
+    unsigned connectionCount() const { return m_connectionCount; }
+
+    //
+    // Thread Safety and Graph Locking:
+    //
+    
+    void setAudioThread(ThreadIdentifier thread) { m_audioThread = thread; } // FIXME: check either not initialized or the same
+    ThreadIdentifier audioThread() const { return m_audioThread; }
+    bool isAudioThread();
+
+    // Returns true only after the audio thread has been started and then shutdown.
+    bool isAudioThreadFinished() { return m_isAudioThreadFinished; }
+    
+    // mustReleaseLock is set to true if we acquired the lock in this method call and caller must unlock(), false if it was previously acquired.
+    void lock(bool& mustReleaseLock);
+
+    // Returns true if we own the lock.
+    // mustReleaseLock is set to true if we acquired the lock in this method call and caller must unlock(), false if it was previously acquired.
+    bool tryLock(bool& mustReleaseLock);
+
+    void unlock();
+
+    // Returns true if this thread owns the context's lock.
+    bool isGraphOwner();
+
+    class AutoLocker {
+    public:
+        AutoLocker(AudioContext* context)
+            : m_context(context)
+        {
+            ASSERT(context);
+            context->lock(m_mustReleaseLock);
+        }
+        
+        ~AutoLocker()
+        {
+            if (m_mustReleaseLock)
+                m_context->unlock();
+        }
+    private:
+        AudioContext* m_context;
+        bool m_mustReleaseLock;
+    };
+    
+    // In AudioNode::deref() a tryLock() is used for calling finishDeref(), but if it fails keep track here.
+    void addDeferredFinishDeref(AudioNode*, AudioNode::RefType);
+
+    // In the audio thread at the start of each render cycle, we'll call handleDeferredFinishDerefs().
+    void handleDeferredFinishDerefs();
+    
+private:
+    AudioContext(Document*);
+    void lazyInitialize();
+    void uninitialize();
+    
+    bool m_isInitialized;
+    bool m_isAudioThreadFinished;
+    bool m_isAudioThreadShutdown;
+
+    Document* m_document;
+
+    // The context itself keeps a reference to all source nodes.  The source nodes, then reference all nodes they're connected to.
+    // In turn, these nodes reference all nodes they're connected to.  All nodes are ultimately connected to the AudioDestinationNode.
+    // When the context dereferences a source node, it will be deactivated from the rendering graph along with all other nodes it is
+    // uniquely connected to.  See the AudioNode::ref() and AudioNode::deref() methods for more details.
+    void refNode(AudioNode*);
+    void derefNode(AudioNode*);
+
+    // When the context goes away, there might still be some sources which haven't finished playing.
+    // Make sure to dereference them here.
+    void derefUnfinishedSourceNodes();
+
+    RefPtr<AudioDestinationNode> m_destinationNode;
+    RefPtr<AudioListener> m_listener;
+
+    // Only accessed in the main thread.
+    Vector<RefPtr<AudioBuffer> > m_allocatedBuffers;
+
+    // Only accessed in the audio thread.
+    Vector<AudioNode*> m_finishedNodes;
+
+    // We don't use RefPtr<AudioNode> here because AudioNode has a more complex ref() / deref() implementation
+    // with an optional argument for refType.  We need to use the special refType: RefTypeConnection
+    // Either accessed when the graph lock is held, or on the main thread when the audio thread has finished.
+    Vector<AudioNode*> m_referencedNodes;
+
+    // Accumulate nodes which need to be deleted at the end of a render cycle (in realtime thread) here.
+    Vector<AudioNode*> m_nodesToDelete;
+
+    Vector<RefPtr<CachedAudio> > m_cachedAudioReferences;
+
+    OwnPtr<AudioBus> m_temporaryMonoBus;
+    OwnPtr<AudioBus> m_temporaryStereoBus;
+
+    unsigned m_connectionCount;
+
+    // Graph locking.
+    Mutex m_contextGraphMutex;
+    volatile ThreadIdentifier m_audioThread;
+    volatile ThreadIdentifier m_graphOwnerThread; // if the lock is held then this is the thread which owns it, otherwise == UndefinedThreadIdentifier
+    
+    // Deferred de-referencing.
+    struct RefInfo {
+        RefInfo(AudioNode* node, AudioNode::RefType refType)
+            : m_node(node)
+            , m_refType(refType)
+        {
+        }
+        AudioNode* m_node;
+        AudioNode::RefType m_refType;
+    };    
+
+    // Only accessed in the audio thread.
+    Vector<RefInfo> m_deferredFinishDerefList;
+};
+
+} // WebCore
+
+#endif // AudioContext_h
diff --git a/WebCore/webaudio/AudioContext.idl b/WebCore/webaudio/AudioContext.idl
new file mode 100644
index 0000000..8951121
--- /dev/null
+++ b/WebCore/webaudio/AudioContext.idl
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 Google Inc. 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ */
+
+module webaudio {
+    interface [
+        Conditional=WEB_AUDIO,
+        CanBeConstructed,
+        CustomConstructFunction,
+        V8CustomConstructor
+    ] AudioContext {
+        // All rendered audio ultimately connects to destination, which represents the audio hardware.
+        readonly attribute AudioDestinationNode destination;
+
+        // All scheduled times are relative to this time in seconds.
+        readonly attribute float currentTime;
+
+        // All AudioNodes in the context run at this sample-rate (in sample-frames per second).
+        readonly attribute float sampleRate;
+
+        // All panning is relative to this listener.
+        readonly attribute AudioListener listener;
+
+        AudioBuffer createBuffer(in unsigned long numberOfChannels, in unsigned long numberOfFrames, in float sampleRate);
+
+        // Source
+        AudioBufferSourceNode createBufferSource();
+
+        // Processing nodes
+        AudioGainNode createGainNode();
+        DelayNode createDelayNode();
+        LowPass2FilterNode createLowPass2Filter();
+        HighPass2FilterNode createHighPass2Filter();
+        AudioPannerNode createPanner();
+        ConvolverNode createConvolver();
+        RealtimeAnalyserNode createAnalyser();
+        JavaScriptAudioNode createJavaScriptNode(in unsigned long bufferSize);
+
+        // Channel splitting and merging
+        AudioChannelSplitter createChannelSplitter();
+        AudioChannelMerger createChannelMerger();
+
+        // FIXME: Temporary - to be replaced with XHR.
+        CachedAudio createAudioRequest(in DOMString url, in boolean mixToMono);
+    };
+}

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list